diff options
207 files changed, 9930 insertions, 2153 deletions
diff --git a/Documentation/aoe/mkshelf.sh b/Documentation/aoe/mkshelf.sh index 8bacf9f2c7c..32615814271 100644 --- a/Documentation/aoe/mkshelf.sh +++ b/Documentation/aoe/mkshelf.sh @@ -8,13 +8,15 @@ fi n_partitions=${n_partitions:-16} dir=$1 shelf=$2 +nslots=16 +maxslot=`echo $nslots 1 - p | dc` MAJOR=152 set -e -minor=`echo 10 \* $shelf \* $n_partitions | bc` +minor=`echo $nslots \* $shelf \* $n_partitions | bc` endp=`echo $n_partitions - 1 | bc` -for slot in `seq 0 9`; do +for slot in `seq 0 $maxslot`; do for part in `seq 0 $endp`; do name=e$shelf.$slot test "$part" != "0" && name=${name}p$part diff --git a/Documentation/fb/intel810.txt b/Documentation/fb/intel810.txt index fd68b162e4a..4f0d6bc789e 100644 --- a/Documentation/fb/intel810.txt +++ b/Documentation/fb/intel810.txt @@ -5,6 +5,7 @@ Intel 810/815 Framebuffer driver March 17, 2002 First Released: July 2001 + Last Update: September 12, 2005 ================================================================ A. Introduction @@ -44,6 +45,8 @@ B. Features - Hardware Cursor Support + - Supports EDID probing either by DDC/I2C or through the BIOS + C. List of available options a. "video=i810fb" @@ -52,14 +55,17 @@ C. List of available options Recommendation: required b. "xres:<value>" - select horizontal resolution in pixels + select horizontal resolution in pixels. (This parameter will be + ignored if 'mode_option' is specified. See 'o' below). Recommendation: user preference (default = 640) c. "yres:<value>" select vertical resolution in scanlines. If Discrete Video Timings - is enabled, this will be ignored and computed as 3*xres/4. + is enabled, this will be ignored and computed as 3*xres/4. (This + parameter will be ignored if 'mode_option' is specified. See 'o' + below) Recommendation: user preference (default = 480) @@ -86,7 +92,8 @@ C. List of available options g. "hsync1/hsync2:<value>" select the minimum and maximum Horizontal Sync Frequency of the monitor in KHz. If a using a fixed frequency monitor, hsync1 must - be equal to hsync2. + be equal to hsync2. If EDID probing is successful, these will be + ignored and values will be taken from the EDID block. Recommendation: check monitor manual for correct values default (29/30) @@ -94,7 +101,8 @@ C. List of available options h. "vsync1/vsync2:<value>" select the minimum and maximum Vertical Sync Frequency of the monitor in Hz. You can also use this option to lock your monitor's refresh - rate. + rate. If EDID probing is successful, these will be ignored and values + will be taken from the EDID block. Recommendation: check monitor manual for correct values (default = 60/60) @@ -154,7 +162,11 @@ C. List of available options Recommendation: do not set (default = not set) - + o. <xres>x<yres>[-<bpp>][@<refresh>] + The driver will now accept specification of boot mode option. If this + is specified, the options 'xres' and 'yres' will be ignored. See + Documentation/fb/modedb.txt for usage. + D. Kernel booting Separate each option/option-pair by commas (,) and the option from its value @@ -176,7 +188,10 @@ will be computed based on the hsync1/hsync2 and vsync1/vsync2 values. IMPORTANT: You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes -better than 640x480 at 60Hz. +better than 640x480 at 60Hz. HOWEVER, if your chipset/display combination +supports I2C and has an EDID block, you can safely exclude hsync1, hsync2, +vsync1 and vsync2 parameters. These parameters will be taken from the EDID +block. E. Module options @@ -217,32 +232,21 @@ F. Setup This is required. The option is under "Character Devices" d. Under "Graphics Support", select "Intel 810/815" either statically - or as a module. Choose "use VESA GTF for video timings" if you - need to maximize the capability of your display. To be on the + or as a module. Choose "use VESA Generalized Timing Formula" if + you need to maximize the capability of your display. To be on the safe side, you can leave this unselected. - e. If you want a framebuffer console, enable it under "Console + e. If you want support for DDC/I2C probing (Plug and Play Displays), + set 'Enable DDC Support' to 'y'. To make this option appear, set + 'use VESA Generalized Timing Formula' to 'y'. + + f. If you want a framebuffer console, enable it under "Console Drivers" - f. Compile your kernel. + g. Compile your kernel. - g. Load the driver as described in section D and E. + h. Load the driver as described in section D and E. - Optional: - h. If you are going to run XFree86 with its native drivers, the - standard XFree86 4.1.0 and 4.2.0 drivers should work as is. - However, there's a bug in the XFree86 i810 drivers. It attempts - to use XAA even when switched to the console. This will crash - your server. I have a fix at this site: - - http://i810fb.sourceforge.net. - - You can either use the patch, or just replace - - /usr/X11R6/lib/modules/drivers/i810_drv.o - - with the one provided at the website. - i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver patch to see the chipset in action (or inaction :-). diff --git a/Documentation/firmware_class/firmware_sample_driver.c b/Documentation/firmware_class/firmware_sample_driver.c index e1c56a7e658..4bef8c25172 100644 --- a/Documentation/firmware_class/firmware_sample_driver.c +++ b/Documentation/firmware_class/firmware_sample_driver.c @@ -32,14 +32,14 @@ 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); + printk(KERN_INFO "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"); + printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n"); if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0) { @@ -61,7 +61,7 @@ static void sample_probe_specific(void) /* NOTE: This currently doesn't work */ - printk("firmware_sample_driver: a ghost device got inserted :)\n"); + printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n"); if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0) { @@ -83,7 +83,7 @@ static void sample_probe_async_cont(const struct firmware *fw, void *context) return; } - printk("firmware_sample_driver: device pointer \"%s\"\n", + printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n", (char *)context); sample_firmware_load(fw->data, fw->size); } diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt new file mode 100644 index 00000000000..b48d11d0326 --- /dev/null +++ b/Documentation/input/appletouch.txt @@ -0,0 +1,84 @@ +Apple Touchpad Driver (appletouch) +---------------------------------- + Copyright (C) 2005 Stelian Pop <stelian@popies.net> + +appletouch is a Linux kernel driver for the USB touchpad found on post +February 2005 Apple Alu Powerbooks. + +This driver is derived from Johannes Berg's appletrackpad driver[1], but it has +been improved in some areas: + * appletouch is a full kernel driver, no userspace program is necessary + * appletouch can be interfaced with the synaptics X11 driver, in order + to have touchpad acceleration, scrolling, etc. + +Credits go to Johannes Berg for reverse-engineering the touchpad protocol, +Frank Arnold for further improvements, and Alex Harper for some additional +information about the inner workings of the touchpad sensors. + +Usage: +------ + +In order to use the touchpad in the basic mode, compile the driver and load +the module. A new input device will be detected and you will be able to read +the mouse data from /dev/input/mice (using gpm, or X11). + +In X11, you can configure the touchpad to use the synaptics X11 driver, which +will give additional functionalities, like acceleration, scrolling, 2 finger +tap for middle button mouse emulation, 3 finger tap for right button mouse +emulation, etc. In order to do this, make sure you're using a recent version of +the synaptics driver (tested with 0.14.2, available from [2]), and configure a +new input device in your X11 configuration file (take a look below for an +example). For additional configuration, see the synaptics driver documentation. + + Section "InputDevice" + Identifier "Synaptics Touchpad" + Driver "synaptics" + Option "SendCoreEvents" "true" + Option "Device" "/dev/input/mice" + Option "Protocol" "auto-dev" + Option "LeftEdge" "0" + Option "RightEdge" "850" + Option "TopEdge" "0" + Option "BottomEdge" "645" + Option "MinSpeed" "0.4" + Option "MaxSpeed" "1" + Option "AccelFactor" "0.02" + Option "FingerLow" "0" + Option "FingerHigh" "30" + Option "MaxTapMove" "20" + Option "MaxTapTime" "100" + Option "HorizScrollDelta" "0" + Option "VertScrollDelta" "30" + Option "SHMConfig" "on" + EndSection + + Section "ServerLayout" + ... + InputDevice "Mouse" + InputDevice "Synaptics Touchpad" + ... + EndSection + +Fuzz problems: +-------------- + +The touchpad sensors are very sensitive to heat, and will generate a lot of +noise when the temperature changes. This is especially true when you power-on +the laptop for the first time. + +The appletouch driver tries to handle this noise and auto adapt itself, but it +is not perfect. If finger movements are not recognized anymore, try reloading +the driver. + +You can activate debugging using the 'debug' module parameter. A value of 0 +deactivates any debugging, 1 activates tracing of invalid samples, 2 activates +full tracing (each sample is being traced): + modprobe appletouch debug=1 + or + echo "1" > /sys/module/appletouch/parameters/debug + +Links: +------ + +[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/ +[2]: http://web.telia.com/~u89404340/touchpad/index.html diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index db2603ceabb..7086f0a90d1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -164,6 +164,15 @@ running once the system is up. over-ride platform specific driver. See also Documentation/acpi-hotkey.txt. + enable_timer_pin_1 [i386,x86-64] + Enable PIN 1 of APIC timer + Can be useful to work around chipset bugs (in particular on some ATI chipsets) + The kernel tries to set a reasonable default. + + disable_timer_pin_1 [i386,x86-64] + Disable PIN 1 of APIC timer + Can be useful to work around chipset bugs. + ad1816= [HW,OSS] Format: <io>,<irq>,<dma>,<dma2> See also Documentation/sound/oss/AD1816. diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt index 729c72d34c8..f86550fe38e 100644 --- a/Documentation/usb/proc_usb_info.txt +++ b/Documentation/usb/proc_usb_info.txt @@ -20,7 +20,7 @@ the /proc/bus/usb/BBB/DDD files. to /etc/fstab. This will mount usbfs at each reboot. You can then issue `cat /proc/bus/usb/devices` to extract - USB device information, and user mode drivers can use usbfs + USB device information, and user mode drivers can use usbfs to interact with USB devices. There are a number of mount options supported by usbfs. @@ -32,7 +32,7 @@ the /proc/bus/usb/BBB/DDD files. still see references to the older "usbdevfs" name. For more information on mounting the usbfs file system, see the -"USB Device Filesystem" section of the USB Guide. The latest copy +"USB Device Filesystem" section of the USB Guide. The latest copy of the USB Guide can be found at http://www.linux-usb.org/ @@ -133,7 +133,7 @@ B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd are the only transfers that reserve bandwidth. Control and bulk transfers use all other bandwidth, including reserved bandwidth that is not used for transfers (such as for short packets). - + The percentage is how much of the "reserved" bandwidth is scheduled by those transfers. For a low or full speed bus (loosely, "USB 1.1"), 90% of the bus bandwidth is reserved. For a high speed bus (loosely, @@ -197,7 +197,7 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA | | |__NumberOfInterfaces | |__ "*" indicates the active configuration (others are " ") |__Config info tag - + USB devices may have multiple configurations, each of which act rather differently. For example, a bus-powered configuration might be much less capable than one that is self-powered. Only @@ -228,7 +228,7 @@ I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss For example, default settings may not use more than a small amount of periodic bandwidth. To use significant fractions of bus bandwidth, drivers must select a non-default altsetting. - + Only one setting for an interface may be active at a time, and only one driver may bind to an interface at a time. Most devices have only one alternate setting per interface. @@ -297,18 +297,21 @@ S: SerialNumber=dce0 C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms + T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4 D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=0451 ProdID=1446 Rev= 1.00 C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms + T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0 D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=04b4 ProdID=0001 Rev= 0.00 C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms + T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=0565 ProdID=0001 Rev= 1.08 diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 678e8f192db..ffe1c062088 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -11,6 +11,11 @@ Machine check If your BIOS doesn't do that it's a good idea to enable though to make sure you log even machine check events that result in a reboot. + mce=tolerancelevel (number) + 0: always panic, 1: panic if deadlock possible, + 2: try to avoid panic, 3: never panic or exit (for testing) + default is 1 + Can be also set using sysfs which is preferable. nomce (for compatibility with i386): same as mce=off diff --git a/MAINTAINERS b/MAINTAINERS index f038dca34ee..a67bf7d315d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -964,6 +964,13 @@ L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.nu/ S: Maintained +HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER +P: Robert Love +M: rlove@rlove.org +M: linux-kernel@vger.kernel.org +W: http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/ +S: Maintained + HARMONY SOUND DRIVER P: Kyle McMartin M: kyle@parisc-linux.org diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index f1b9d2a46da..1ae2aeeda18 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -7,6 +7,7 @@ #include <linux/pci.h> #include <asm/pci-direct.h> #include <asm/acpi.h> +#include <asm/apic.h> static int __init check_bridge(int vendor, int device) { @@ -15,6 +16,15 @@ static int __init check_bridge(int vendor, int device) if (vendor == PCI_VENDOR_ID_NVIDIA) { acpi_skip_timer_override = 1; } +#ifdef CONFIG_X86_LOCAL_APIC + /* + * ATI IXP chipsets get double timer interrupts. + * For now just do this for all ATI chipsets. + * FIXME: this needs to be checked for the non ACPI case too. + */ + if (vendor == PCI_VENDOR_ID_ATI) + disable_timer_pin_1 = 1; +#endif return 0; } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 3aad0383966..9e24f7b207e 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -319,7 +319,7 @@ work_notifysig: # deal with pending signals and # vm86-space xorl %edx, %edx call do_notify_resume - jmp restore_all + jmp resume_userspace ALIGN work_notifysig_v86: @@ -329,7 +329,7 @@ work_notifysig_v86: movl %eax, %esp xorl %edx, %edx call do_notify_resume - jmp restore_all + jmp resume_userspace # perform syscall exit tracing ALIGN diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 35d3ce26a54..378313b0cce 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -60,6 +60,8 @@ int sis_apic_bug = -1; */ int nr_ioapic_registers[MAX_IO_APICS]; +int disable_timer_pin_1 __initdata; + /* * Rough estimation of how many shared IRQs there are, can * be changed anytime. @@ -2211,6 +2213,8 @@ static inline void check_timer(void) setup_nmi(); enable_8259A_irq(0); } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); return; } clear_IO_APIC_pin(0, pin1); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index f3d808451d2..dc39ca6a7ec 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -851,6 +851,11 @@ static void __init parse_cmdline_early (char ** cmdline_p) #endif #ifdef CONFIG_X86_LOCAL_APIC + if (!memcmp(from, "disable_timer_pin_1", 19)) + disable_timer_pin_1 = 1; + if (!memcmp(from, "enable_timer_pin_1", 18)) + disable_timer_pin_1 = -1; + /* disable IO-APIC */ else if (!memcmp(from, "noapic", 6)) disable_ioapic_setup(); diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c index 7b3b27d6440..516bf5653b0 100644 --- a/arch/i386/kernel/srat.c +++ b/arch/i386/kernel/srat.c @@ -213,12 +213,18 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c node_end_pfn[nid] = memory_chunk->end_pfn; } +static u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */ + +int pxm_to_node(int pxm) +{ + return pxm_to_nid_map[pxm]; +} + /* Parse the ACPI Static Resource Affinity Table */ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) { u8 *start, *end, *p; int i, j, nid; - u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */ u8 nid_to_pxm_map[MAX_NUMNODES];/* logical node ID to _PXM map */ start = (u8 *)(&(sratp->reserved) + 1); /* skip header */ diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c index 42913f43feb..2941674f35e 100644 --- a/arch/i386/pci/acpi.c +++ b/arch/i386/pci/acpi.c @@ -3,16 +3,31 @@ #include <linux/init.h> #include <linux/irq.h> #include <asm/hw_irq.h> +#include <asm/numa.h> #include "pci.h" struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { + struct pci_bus *bus; + if (domain != 0) { printk(KERN_WARNING "PCI: Multiple domains not supported\n"); return NULL; } - return pcibios_scan_root(busnum); + bus = pcibios_scan_root(busnum); +#ifdef CONFIG_ACPI_NUMA + if (bus != NULL) { + int pxm = acpi_get_pxm(device->handle); + if (pxm >= 0) { + bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm); + printk("bus %d -> pxm %d -> node %ld\n", + busnum, pxm, (long)(bus->sysdata)); + } + } +#endif + + return bus; } extern int pci_routeirq; diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 60f0e7a1162..dfbf80cff83 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -127,13 +127,6 @@ static int __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) goto out; - /* Kludge for now. Don't use mmconfig on AMD systems because - those have some busses where mmconfig doesn't work, - and we don't parse ACPI MCFG well enough to handle that. - Remove when proper handling is added. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - goto out; - printk(KERN_INFO "PCI: Using MMCONFIG\n"); raw_pci_ops = &pci_mmcfg; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index e29a8a55486..3fa67ecebc8 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -2327,7 +2327,7 @@ sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count) ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S new file mode 100644 index 00000000000..a5c639a51ee --- /dev/null +++ b/arch/m68knommu/platform/68360/head-ram.S @@ -0,0 +1,408 @@ +/* arch/m68knommu/platform/68360/head-ram.S + * + * Startup code for Motorola 68360 + * + * Copyright 2001 (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie <mleslie@lineo.com> + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne <jeff@uclinux.org>, + * + */ +#define ASSEMBLY +#include <linux/config.h> + +.global _stext +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000002 +#define SIM_BR0_MASK 0x00000001 + + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include <asm/m68360_regs.h> + + +/* + * By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. + */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #__ramend, %sp /*set up stack at the end of DRAM:*/ + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + + /* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + + /* to do: Determine cause of reset */ + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + /* Wait for the PLL to settle */ + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + + /* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* Set up Global Memory Register (GMR) */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #__ramend, %d0 + subi.l #__ramstart, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__ramstart, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + +configure_chip_select_1: + move.l #__rom_end, %d0 + subi.l #__rom_start, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR1_MASK, %d0 + move.l %d0, OR1 + + move.l #__rom_start, %d0 + ori.l #SIM_BR1_MASK, %d0 + move.l %d0, BR1 + + move.w #MCU_SIM_PEPAR, PEPAR + + /* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #_stext, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #_edata, %a1 + blt LD1 + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #_ebss, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__rom_end, %d0 + sub.l #__rom_start, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + +_exit: + jmp _exit + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 +_dprbase: + .long 0xffffe000 + + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long __ramend /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependent on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S new file mode 100644 index 00000000000..0da357a4cfe --- /dev/null +++ b/arch/m68knommu/platform/68360/head-rom.S @@ -0,0 +1,420 @@ +/* arch/m68knommu/platform/68360/head-rom.S + * + * Startup code for Motorola 68360 + * + * Copyright (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie <mleslie@lineo.com> + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne <jeff@uclinux.org>, + * + */ +#include <linux/config.h> + +.global _stext +.global _sbss +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) + +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) + +#define OR2 (_dprbase + REGB + 0x0074) +#define BR2 (_dprbase + REGB + 0x0070) + +#define OR3 (_dprbase + REGB + 0x0084) +#define BR3 (_dprbase + REGB + 0x0080) + +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) + +#define OR5 (_dprbase + REGB + 0x00A4) +#define BR5 (_dprbase + REGB + 0x00A0) + +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) + +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000000 +#define SIM_BR0_MASK 0x00000001 + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include <asm/m68360_regs.h> + + +/* + * By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. + */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #__ramend, %sp /* set up stack at the end of DRAM:*/ + + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + + /* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + + /* to do: Determine cause of reset */ + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + * or + * (value + 1)*osc = system clock + * You do not need to divide the oscillator by 128 unless you want to. + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + /* Wait for the PLL to settle */ + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + + /* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* Set up Global Memory Register (GMR) */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #0x00400000, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__rom_start, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + + move.l #0x0, BR1 + move.l #0x0, BR2 + move.l #0x0, BR3 + move.l #0x0, BR4 + move.l #0x0, BR5 + move.l #0x0, BR6 + move.l #0x0, BR7 + + move.w #MCU_SIM_PEPAR, PEPAR + + /* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #_etext, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #_edata, %a1 + blt LD1 + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #_ebss, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__rom_end, %d0 + sub.l #__rom_start, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + +_exit: + jmp _exit + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 +_dprbase: + .long 0xffffe000 + + + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long __ramend /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependent on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 356e4fd9a94..fbc273c32bc 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -252,7 +252,7 @@ unsigned long __init find_and_init_phbs(void) phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); if (phb == NULL) return -ENOMEM; - pci_setup_pci_controller(phb); + pci_setup_pci_controller(phb); phb->pci_mem_offset = phb->local_number = bus; phb->first_busno = bus; diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 5a8b4d8c2dd..1d297e0edfc 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -283,7 +283,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; hose->ops = &u3_agp_pci_ops; hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); @@ -315,24 +315,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -346,25 +346,25 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev); pci_setup_phb_io(hose, primary); - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 9490b6c5b17..bfadccc7b8b 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -590,6 +590,13 @@ static int pseries_shared_idle(void) return 0; } +static int pSeries_pci_probe_mode(struct pci_bus *bus) +{ + if (systemcfg->platform & PLATFORM_LPAR) + return PCI_PROBE_DEVTREE; + return PCI_PROBE_NORMAL; +} + struct machdep_calls __initdata pSeries_md = { .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, @@ -597,6 +604,7 @@ struct machdep_calls __initdata pSeries_md = { .get_cpuinfo = pSeries_get_cpuinfo, .log_error = pSeries_log_error, .pcibios_fixup = pSeries_final_fixup, + .pci_probe_mode = pSeries_pci_probe_mode, .irq_bus_setup = pSeries_irq_bus_setup, .restart = rtas_restart, .power_off = rtas_power_off, diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 79c7f322366..d2c7e2c4733 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -272,6 +272,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned long start_here = __pa((u32)*((unsigned long *) pSeries_secondary_smp_init)); unsigned int pcpu; + int start_cpu; if (cpu_isset(lcpu, of_spin_map)) /* Already started by OF and sitting in spin loop */ @@ -282,12 +283,20 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) /* Fixup atomic count: it exited inside IRQ handler. */ paca[lcpu].__current->thread_info->preempt_count = 0; - status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL, - pcpu, start_here, lcpu); + /* + * If the RTAS start-cpu token does not exist then presume the + * cpu is already spinning. + */ + start_cpu = rtas_token("start-cpu"); + if (start_cpu == RTAS_UNKNOWN_SERVICE) + return 1; + + status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu); if (status != 0) { printk(KERN_ERR "start-cpu failed: %i\n", status); return 0; } + return 1; } diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 8447dcc2c2b..861138ad092 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -51,6 +51,10 @@ unsigned long io_page_mask; EXPORT_SYMBOL(io_page_mask); +#ifdef CONFIG_PPC_MULTIPLATFORM +static void fixup_resource(struct resource *res, struct pci_dev *dev); +static void do_bus_setup(struct pci_bus *bus); +#endif unsigned int pcibios_assign_all_busses(void) { @@ -225,10 +229,287 @@ static void __init pcibios_claim_of_setup(void) } #endif +#ifdef CONFIG_PPC_MULTIPLATFORM +static u32 get_int_prop(struct device_node *np, const char *name, u32 def) +{ + u32 *prop; + int len; + + prop = (u32 *) get_property(np, name, &len); + if (prop && len >= 4) + return *prop; + return def; +} + +static unsigned int pci_parse_of_flags(u32 addr0) +{ + unsigned int flags = 0; + + if (addr0 & 0x02000000) { + flags |= IORESOURCE_MEM; + if (addr0 & 0x40000000) + flags |= IORESOURCE_PREFETCH; + } else if (addr0 & 0x01000000) + flags |= IORESOURCE_IO; + return flags; +} + +#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) + +static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) +{ + u64 base, size; + unsigned int flags; + struct resource *res; + u32 *addrs, i; + int proplen; + + addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); + if (!addrs) + return; + for (; proplen >= 20; proplen -= 20, addrs += 5) { + flags = pci_parse_of_flags(addrs[0]); + if (!flags) + continue; + base = GET_64BIT(addrs, 1); + size = GET_64BIT(addrs, 3); + if (!size) + continue; + i = addrs[0] & 0xff; + if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { + res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; + } else if (i == dev->rom_base_reg) { + res = &dev->resource[PCI_ROM_RESOURCE]; + flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + } else { + printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); + continue; + } + res->start = base; + res->end = base + size - 1; + res->flags = flags; + res->name = pci_name(dev); + fixup_resource(res, dev); + } +} + +static struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn) +{ + struct pci_dev *dev; + const char *type; + + dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + if (!dev) + return NULL; + type = get_property(node, "device_type", NULL); + if (type == NULL) + type = ""; + + memset(dev, 0, sizeof(struct pci_dev)); + dev->bus = bus; + dev->sysdata = node; + dev->dev.parent = bus->bridge; + dev->dev.bus = &pci_bus_type; + dev->devfn = devfn; + dev->multifunction = 0; /* maybe a lie? */ + + dev->vendor = get_int_prop(node, "vendor-id", 0xffff); + dev->device = get_int_prop(node, "device-id", 0xffff); + dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); + dev->subsystem_device = get_int_prop(node, "subsystem-id", 0); + + dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/ + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dev->class = get_int_prop(node, "class-code", 0); + + dev->current_state = 4; /* unknown power state */ + + if (!strcmp(type, "pci")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; + dev->irq = NO_IRQ; + if (node->n_intrs > 0) { + dev->irq = node->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + dev->irq); + } + } + + pci_parse_of_addrs(node, dev); + + pci_device_add(dev, bus); + + /* XXX pci_scan_msi_device(dev); */ + + return dev; +} + +static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); + +static void __devinit of_scan_bus(struct device_node *node, + struct pci_bus *bus) +{ + struct device_node *child = NULL; + u32 *reg; + int reglen, devfn; + struct pci_dev *dev; + + while ((child = of_get_next_child(node, child)) != NULL) { + reg = (u32 *) get_property(child, "reg", ®len); + if (reg == NULL || reglen < 20) + continue; + devfn = (reg[0] >> 8) & 0xff; + /* create a new pci_dev for this device */ + dev = of_create_pci_dev(child, bus, devfn); + if (!dev) + continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + of_scan_pci_bridge(child, dev); + } + + do_bus_setup(bus); +} + +static void __devinit of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev) +{ + struct pci_bus *bus; + u32 *busrange, *ranges; + int len, i, mode; + struct resource *res; + unsigned int flags; + u64 size; + + /* parse bus-range property */ + busrange = (u32 *) get_property(node, "bus-range", &len); + if (busrange == NULL || len != 8) { + printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", + node->full_name); + return; + } + ranges = (u32 *) get_property(node, "ranges", &len); + if (ranges == NULL) { + printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", + node->full_name); + return; + } + + bus = pci_add_new_bus(dev->bus, dev, busrange[0]); + if (!bus) { + printk(KERN_ERR "Failed to create pci bus for %s\n", + node->full_name); + return; + } + + bus->primary = dev->bus->number; + bus->subordinate = busrange[1]; + bus->bridge_ctl = 0; + bus->sysdata = node; + + /* parse ranges property */ + /* PCI #address-cells == 3 and #size-cells == 2 always */ + res = &dev->resource[PCI_BRIDGE_RESOURCES]; + for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { + res->flags = 0; + bus->resource[i] = res; + ++res; + } + i = 1; + for (; len >= 32; len -= 32, ranges += 8) { + flags = pci_parse_of_flags(ranges[0]); + size = GET_64BIT(ranges, 6); + if (flags == 0 || size == 0) + continue; + if (flags & IORESOURCE_IO) { + res = bus->resource[0]; + if (res->flags) { + printk(KERN_ERR "PCI: ignoring extra I/O range" + " for bridge %s\n", node->full_name); + continue; + } + } else { + if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { + printk(KERN_ERR "PCI: too many memory ranges" + " for bridge %s\n", node->full_name); + continue; + } + res = bus->resource[i]; + ++i; + } + res->start = GET_64BIT(ranges, 1); + res->end = res->start + size - 1; + res->flags = flags; + fixup_resource(res, dev); + } + sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), + bus->number); + + mode = PCI_PROBE_NORMAL; + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) + of_scan_bus(node, bus); + else if (mode == PCI_PROBE_NORMAL) + pci_scan_child_bus(bus); +} +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +static void __devinit scan_phb(struct pci_controller *hose) +{ + struct pci_bus *bus; + struct device_node *node = hose->arch_data; + int i, mode; + struct resource *res; + + bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); + if (bus == NULL) { + printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", + hose->global_number); + return; + } + bus->secondary = hose->first_busno; + hose->bus = bus; + + bus->resource[0] = res = &hose->io_resource; + if (res->flags && request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request PCI IO region " + "on PCI domain %04x\n", hose->global_number); + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request PCI memory region " + "on PCI domain %04x\n", hose->global_number); + } + + mode = PCI_PROBE_NORMAL; +#ifdef CONFIG_PPC_MULTIPLATFORM + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) { + bus->subordinate = hose->last_busno; + of_scan_bus(node, bus); + } +#endif /* CONFIG_PPC_MULTIPLATFORM */ + if (mode == PCI_PROBE_NORMAL) + hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + pci_bus_add_devices(bus); +} + static int __init pcibios_init(void) { struct pci_controller *hose, *tmp; - struct pci_bus *bus; /* For now, override phys_mem_access_prot. If we need it, * later, we may move that initialization to each ppc_md @@ -242,13 +523,8 @@ static int __init pcibios_init(void) printk("PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - hose->last_busno = 0xff; - bus = pci_scan_bus(hose->first_busno, hose->ops, - hose->arch_data); - hose->bus = bus; - hose->last_busno = bus->subordinate; - } + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + scan_phb(hose); #ifndef CONFIG_PPC_ISERIES if (pci_probe_only) @@ -820,120 +1096,89 @@ void phbs_remap_io(void) /* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. + * XXX this can go now, we use the OF device tree in all the + * cases that caused problems. -- paulus */ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) { - struct device_node *busdn, *dn; - - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ - - if (busdn == NULL) - return 0; - - /* - * Check to see if there is any of the 8 functions are in the - * device tree. If they are then we need to scan all the - * functions of this slot. - */ - for (dn = busdn->child; dn; dn = dn->sibling) { - struct pci_dn *pdn = dn->data; - if (pdn && (pdn->devfn >> 3) == (devfn >> 3)) - return 1; - } - return 0; } +static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + unsigned long start, end, mask, offset; + + if (res->flags & IORESOURCE_IO) { + offset = (unsigned long)hose->io_base_virt - pci_io_base; + + start = res->start += offset; + end = res->end += offset; + + /* Need to allow IO access to pages that are in the + ISA range */ + if (start < MAX_ISA_PORT) { + if (end > MAX_ISA_PORT) + end = MAX_ISA_PORT; + + start >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + + /* get the range of pages for the map */ + mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1); + io_page_mask |= mask; + } + } else if (res->flags & IORESOURCE_MEM) { + res->start += hose->pci_mem_offset; + res->end += hose->pci_mem_offset; + } +} void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) + struct pci_bus *bus) { /* Update device resources. */ - struct pci_controller *hose = pci_bus_to_host(bus); int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - - pci_io_base; - unsigned long start, end, mask; - - start = dev->resource[i].start += offset; - end = dev->resource[i].end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1))-1) ^ ((1 << start)-1); - io_page_mask |= mask; - } - } - else if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += hose->pci_mem_offset; - dev->resource[i].end += hose->pci_mem_offset; - } - } + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (dev->resource[i].flags) + fixup_resource(&dev->resource[i], dev); } EXPORT_SYMBOL(pcibios_fixup_device_resources); -void __devinit pcibios_fixup_bus(struct pci_bus *bus) +static void __devinit do_bus_setup(struct pci_bus *bus) { - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_dev *dev = bus->self; - struct resource *res; - int i; + struct pci_dev *dev; - if (!dev) { - /* Root bus. */ + ppc_md.iommu_bus_setup(bus); - hose->bus = bus; - bus->resource[0] = res = &hose->io_resource; + list_for_each_entry(dev, &bus->devices, bus_list) + ppc_md.iommu_dev_setup(dev); - if (res->flags && request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request IO on " - "PCI domain %d\n", pci_domain_nr(bus)); + if (ppc_md.irq_bus_setup) + ppc_md.irq_bus_setup(bus); +} - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request MEM on " - "PCI domain %d\n", - pci_domain_nr(bus)); - } - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + if (dev && pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); } - ppc_md.iommu_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - ppc_md.iommu_dev_setup(dev); - - if (ppc_md.irq_bus_setup) - ppc_md.irq_bus_setup(bus); + do_bus_setup(bus); if (!pci_probe_only) return; - list_for_each_entry(dev, &bus->devices, bus_list) { + list_for_each_entry(dev, &bus->devices, bus_list) if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) pcibios_fixup_device_resources(dev, bus); - } } EXPORT_SYMBOL(pcibios_fixup_bus); diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index d37bff2d7d4..dc40a0cad0b 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -388,7 +388,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; has_uninorth = 1; hose->ops = ¯isc_pci_ops; @@ -473,7 +473,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) continue; } cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); hose->mem_resources[cur].name = np->full_name; hose->mem_resources[cur].flags = IORESOURCE_MEM; @@ -603,24 +603,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -634,24 +634,24 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pmac_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pmac_process_bridge_OF_ranges(hose, dev, primary); + + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index e7f695dcd8c..325426c7bed 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -477,6 +477,18 @@ static int __init pmac_probe(int platform) return 1; } +static int pmac_probe_mode(struct pci_bus *bus) +{ + struct device_node *node = bus->sysdata; + + /* We need to use normal PCI probing for the AGP bus, + since the device for the AGP bridge isn't in the tree. */ + if (bus->self == NULL && device_is_compatible(node, "u3-agp")) + return PCI_PROBE_NORMAL; + + return PCI_PROBE_DEVTREE; +} + struct machdep_calls __initdata pmac_md = { #ifdef CONFIG_HOTPLUG_CPU .cpu_die = generic_mach_cpu_die, @@ -488,6 +500,7 @@ struct machdep_calls __initdata pmac_md = { .init_IRQ = pmac_init_IRQ, .get_irq = mpic_get_irq, .pcibios_fixup = pmac_pcibios_fixup, + .pci_probe_mode = pmac_probe_mode, .restart = pmac_restart, .power_off = pmac_power_off, .halt = pmac_halt, diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 7a7e027653a..887005358eb 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -54,6 +54,7 @@ #include <asm/sections.h> #include <asm/tlbflush.h> #include <asm/time.h> +#include <asm/plpar_wrappers.h> #ifndef CONFIG_SMP struct task_struct *last_task_used_math = NULL; @@ -163,7 +164,30 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) #endif /* CONFIG_ALTIVEC */ +static void set_dabr_spr(unsigned long val) +{ + mtspr(SPRN_DABR, val); +} + +int set_dabr(unsigned long dabr) +{ + int ret = 0; + + if (firmware_has_feature(FW_FEATURE_XDABR)) { + /* We want to catch accesses from kernel and userspace */ + unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; + ret = plpar_set_xdabr(dabr, flags); + } else if (firmware_has_feature(FW_FEATURE_DABR)) { + ret = plpar_set_dabr(dabr); + } else { + set_dabr_spr(dabr); + } + + return ret; +} + DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); +static DEFINE_PER_CPU(unsigned long, current_dabr); struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) @@ -198,6 +222,11 @@ struct task_struct *__switch_to(struct task_struct *prev, new->thread.regs->msr |= MSR_VEC; #endif /* CONFIG_ALTIVEC */ + if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { + set_dabr(new->thread.dabr); + __get_cpu_var(current_dabr) = new->thread.dabr; + } + flush_tlb_pending(); new_thread = &new->thread; @@ -334,6 +363,11 @@ void flush_thread(void) last_task_used_altivec = NULL; #endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_SMP */ + + if (current->thread.dabr) { + current->thread.dabr = 0; + set_dabr(0); + } } void diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 2993f108d96..85ed3188a91 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -206,6 +207,19 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, + (unsigned long __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; @@ -274,6 +288,20 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 16436426c7e..fb8c22d6084 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -337,6 +338,19 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, (u32 __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; @@ -405,9 +419,23 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned int __user *) data); + break; + +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif default: ret = ptrace_request(child, request, addr, data); diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 3c00f7bfc1b..41b97dc9cc0 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c @@ -59,8 +59,6 @@ char mce_data_buf[RTAS_ERROR_LOG_MAX] /* This is true if we are using the firmware NMI handler (typically LPAR) */ extern int fwnmi_active; -extern void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); - static int ras_get_sensor_state_token; static int ras_check_exception_token; diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index bfa8791c980..5ac48bd6489 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1064,8 +1064,6 @@ void __init setup_arch(char **cmdline_p) #define PPC64_LINUX_FUNCTION 0x0f000000 #define PPC64_IPL_MESSAGE 0xc0000000 #define PPC64_TERM_MESSAGE 0xb0000000 -#define PPC64_ATTN_MESSAGE 0xa0000000 -#define PPC64_DUMP_MESSAGE 0xd0000000 static void ppc64_do_msg(unsigned int src, const char *msg) { @@ -1093,20 +1091,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -/* Print something that needs attention (device error, etc) */ -void ppc64_attention_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); - printk("[attention]%04x %s\n", src, msg); -} - -/* Print a dump progress message. */ -void ppc64_dump_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); - printk("[dump]%04x %s\n", src, msg); -} - /* This should only be called on processor 0 during calibrate decr */ void __init setup_default_decr(void) { diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 49a79a55c32..347112cca3c 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -550,6 +550,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* Whee! Actually deliver the signal. */ if (TRAP(regs) == 0x0C00) syscall_restart(regs, &ka); + + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + return handle_signal(signr, &ka, &info, oldset, regs); } diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 46f4d6cc7fc..a8b7a5a56bb 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -970,6 +970,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) newsp = regs->gpr[1]; newsp &= ~0xfUL; + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + /* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags & SA_SIGINFO) ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index d9dc6f28d05..daf93885dcf 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -38,7 +38,7 @@ static void xics_mask_and_ack_irq(unsigned int irq); static void xics_end_irq(unsigned int irq); static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask); -struct hw_interrupt_type xics_pic = { +static struct hw_interrupt_type xics_pic = { .typename = " XICS ", .startup = xics_startup, .enable = xics_enable_irq, @@ -48,7 +48,7 @@ struct hw_interrupt_type xics_pic = { .set_affinity = xics_set_affinity }; -struct hw_interrupt_type xics_8259_pic = { +static struct hw_interrupt_type xics_8259_pic = { .typename = " XICS/8259", .ack = xics_mask_and_ack_irq, }; @@ -89,9 +89,8 @@ static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; static int xics_irq_8259_cascade = 0; static int xics_irq_8259_cascade_real = 0; static unsigned int default_server = 0xFF; -/* also referenced in smp.c... */ -unsigned int default_distrib_server = 0; -unsigned int interrupt_server_size = 8; +static unsigned int default_distrib_server = 0; +static unsigned int interrupt_server_size = 8; /* * XICS only has a single IPI, so encode the messages per CPU @@ -99,10 +98,10 @@ unsigned int interrupt_server_size = 8; struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; /* RTAS service tokens */ -int ibm_get_xive; -int ibm_set_xive; -int ibm_int_on; -int ibm_int_off; +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; typedef struct { int (*xirr_info_get)(int cpu); @@ -284,16 +283,17 @@ static void xics_enable_irq(unsigned int virq) call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_set_xive " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " + "returned %d\n", irq, call_status); + printk("set_xive %x, server %x\n", ibm_set_xive, server); return; } /* Now unmask the interrupt (often a no-op) */ call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_int_on " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " + "returned %d\n", irq, call_status); return; } } @@ -308,8 +308,8 @@ static void xics_disable_real_irq(unsigned int irq) call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_disable_real_irq: irq=%d: " - "ibm_int_off returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_real_irq: irq=%u: " + "ibm_int_off returned %d\n", irq, call_status); return; } @@ -317,8 +317,8 @@ static void xics_disable_real_irq(unsigned int irq) /* Have to set XIVE to 0xff to be able to remove a slot */ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff); if (call_status != 0) { - printk(KERN_ERR "xics_disable_irq: irq=%d: ibm_set_xive(0xff)" - " returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" + " returned %d\n", irq, call_status); return; } } @@ -380,7 +380,7 @@ int xics_get_irq(struct pt_regs *regs) if (irq == NO_IRQ) irq = real_irq_to_virt_slowpath(vec); if (irq == NO_IRQ) { - printk(KERN_ERR "Interrupt %d (real) is invalid," + printk(KERN_ERR "Interrupt %u (real) is invalid," " disabling it.\n", vec); xics_disable_real_irq(vec); } else @@ -622,7 +622,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,get-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " "returns %d\n", irq, status); return; } @@ -641,7 +641,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) irq, newmask, xics_status[1]); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,set-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " "returns %d\n", irq, status); return; } @@ -720,7 +720,7 @@ void xics_migrate_irqs_away(void) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "migrate_irqs_away: irq=%d " + printk(KERN_ERR "migrate_irqs_away: irq=%u " "ibm,get-xive returns %d\n", virq, status); goto unlock; @@ -734,7 +734,7 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != get_hard_smp_processor_id(cpu)) goto unlock; - printk(KERN_WARNING "IRQ %d affinity broken off cpu %u\n", + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", virq, cpu); /* Reset affinity to all cpus */ diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c index 772f0714a5b..7fbc68bbb73 100644 --- a/arch/ppc64/mm/fault.c +++ b/arch/ppc64/mm/fault.c @@ -77,6 +77,28 @@ static int store_updates_sp(struct pt_regs *regs) return 0; } +static void do_dabr(struct pt_regs *regs, unsigned long error_code) +{ + siginfo_t info; + + if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, + 11, SIGSEGV) == NOTIFY_STOP) + return; + + if (debugger_dabr_match(regs)) + return; + + /* Clear the DABR */ + set_dabr(0); + + /* Deliver the signal to userspace */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + info.si_addr = (void __user *)regs->nip; + force_sig_info(SIGTRAP, &info, current); +} + /* * The error_code parameter is * - DSISR for a non-SLB data access fault, @@ -111,12 +133,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && (address >= TASK_SIZE)) return SIGSEGV; - if (error_code & DSISR_DABRMATCH) { - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return 0; - if (debugger_dabr_match(regs)) - return 0; + if (error_code & DSISR_DABRMATCH) { + do_dabr(regs, error_code); + return 0; } if (in_atomic() || mm == NULL) { diff --git a/arch/ppc64/xmon/privinst.h b/arch/ppc64/xmon/privinst.h index 183c3e40025..02eb40dac0b 100644 --- a/arch/ppc64/xmon/privinst.h +++ b/arch/ppc64/xmon/privinst.h @@ -46,7 +46,6 @@ GSETSPR(287, pvr) GSETSPR(1008, hid0) GSETSPR(1009, hid1) GSETSPR(1010, iabr) -GSETSPR(1013, dabr) GSETSPR(1023, pir) static inline void store_inst(void *p) diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 45908b10acd..74e63a886a6 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -586,6 +586,8 @@ int xmon_dabr_match(struct pt_regs *regs) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) return 0; + if (dabr.enabled == 0) + return 0; xmon_core(regs, 0); return 1; } @@ -628,20 +630,6 @@ int xmon_fault_handler(struct pt_regs *regs) return 0; } -/* On systems with a hypervisor, we can't set the DABR - (data address breakpoint register) directly. */ -static void set_controlled_dabr(unsigned long val) -{ -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { - int rc = plpar_hcall_norets(H_SET_DABR, val); - if (rc != H_Success) - xmon_printf("Warning: setting DABR failed (%d)\n", rc); - } else -#endif - set_dabr(val); -} - static struct bpt *at_breakpoint(unsigned long pc) { int i; @@ -728,7 +716,7 @@ static void insert_bpts(void) static void insert_cpu_bpts(void) { if (dabr.enabled) - set_controlled_dabr(dabr.address | (dabr.enabled & 7)); + set_dabr(dabr.address | (dabr.enabled & 7)); if (iabr && cpu_has_feature(CPU_FTR_IABR)) set_iabr(iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); @@ -756,7 +744,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { - set_controlled_dabr(0); + set_dabr(0); if (cpu_has_feature(CPU_FTR_IABR)) set_iabr(0); } diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 18610cea03a..ed877d0f27e 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -678,7 +678,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile index f4399c701b7..18c6e915d69 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -46,7 +46,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) - @echo 'Kernel: $@ is ready' + @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index b38d5b8b5fb..0e10fd84c7c 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c @@ -83,7 +83,7 @@ static unsigned char *real_mode; /* Pointer to real-mode data */ #endif #define SCREEN_INFO (*(struct screen_info *)(real_mode+0)) -extern char input_data[]; +extern unsigned char input_data[]; extern int input_len; static long bytes_out = 0; @@ -288,7 +288,7 @@ void setup_normal_output_buffer(void) #else if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory"); #endif - output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */ + output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */ free_mem_end_ptr = (long)real_mode; } @@ -305,7 +305,7 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv) #else if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); #endif - mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; + mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; low_buffer_size = low_buffer_end - LOW_BUFFER_START; diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index bf57e2362bf..f8db7e500fb 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,11 +1,12 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc6-git3 -# Fri Aug 12 16:40:34 2005 +# Linux kernel version: 2.6.13-git11 +# Mon Sep 12 16:16:16 2005 # CONFIG_X86_64=y CONFIG_64BIT=y CONFIG_X86=y +CONFIG_SEMAPHORE_SLEEPERS=y CONFIG_MMU=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y @@ -13,6 +14,7 @@ CONFIG_X86_CMPXCHG=y CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -26,6 +28,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -37,6 +40,7 @@ CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y @@ -102,6 +106,7 @@ CONFIG_DISCONTIGMEM_MANUAL=y CONFIG_DISCONTIGMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=32 @@ -122,6 +127,7 @@ CONFIG_HZ=250 CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_ISA_DMA_API=y +CONFIG_GENERIC_PENDING_IRQ=y # # Power management options @@ -194,7 +200,6 @@ CONFIG_UNORDERED_IO=y # CONFIG_PCIEPORTBUS is not set CONFIG_PCI_MSI=y # CONFIG_PCI_LEGACY_PROC is not set -# CONFIG_PCI_NAMES is not set # CONFIG_PCI_DEBUG is not set # @@ -234,7 +239,10 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y -# CONFIG_IP_PNP is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set @@ -244,8 +252,8 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -CONFIG_IP_TCPDIAG_IPV6=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y CONFIG_IPV6=y @@ -258,6 +266,11 @@ CONFIG_IPV6=y # CONFIG_NETFILTER is not set # +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set @@ -280,9 +293,11 @@ CONFIG_IPV6=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set # # Device Drivers @@ -329,7 +344,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" CONFIG_LBD=y # CONFIG_CDROM_PKTCDVD is not set @@ -409,6 +423,7 @@ CONFIG_IDEDMA_AUTO=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set @@ -432,7 +447,7 @@ CONFIG_BLK_DEV_SD=y # # SCSI Transport Attributes # -# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set @@ -458,6 +473,7 @@ CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_AHCI is not set # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=y +# CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set # CONFIG_SCSI_SATA_PROMISE is not set # CONFIG_SCSI_SATA_QSTOR is not set @@ -537,6 +553,11 @@ CONFIG_TUN=y # CONFIG_ARCNET is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -586,6 +607,7 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set @@ -595,6 +617,7 @@ CONFIG_TIGON3=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set CONFIG_S2IO=m # CONFIG_S2IO_NAPI is not set @@ -749,7 +772,6 @@ CONFIG_MAX_RAW_DEVS=256 # I2C support # # CONFIG_I2C is not set -# CONFIG_I2C_SENSOR is not set # # Dallas's 1-wire bus @@ -760,6 +782,7 @@ CONFIG_MAX_RAW_DEVS=256 # Hardware Monitoring support # CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -768,6 +791,10 @@ CONFIG_HWMON=y # CONFIG_IBM_ASM is not set # +# Multimedia Capabilities Port drivers +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -858,9 +885,8 @@ CONFIG_USB_UHCI_HCD=y # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set CONFIG_USB_PRINTER=y @@ -877,6 +903,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set # # USB Input Devices @@ -893,6 +920,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_MTOUCH is not set # CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_KEYSPAN_REMOTE is not set @@ -976,6 +1004,8 @@ CONFIG_USB_MON=y # Firmware Drivers # # CONFIG_EDD is not set +# CONFIG_DELL_RBU is not set +CONFIG_DCDBAS=m # # File systems @@ -1000,10 +1030,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y # CONFIG_REISERFS_FS_SECURITY is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1012,6 +1038,7 @@ CONFIG_INOTIFY=y CONFIG_DNOTIFY=y CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -1037,12 +1064,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1074,6 +1100,7 @@ CONFIG_NFSD_V3=y # CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y @@ -1086,6 +1113,7 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -1150,6 +1178,7 @@ CONFIG_OPROFILE=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=18 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1157,6 +1186,7 @@ CONFIG_LOG_BUF_SHIFT=18 # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y +# CONFIG_FRAME_POINTER is not set CONFIG_INIT_DEBUG=y # CONFIG_IOMMU_DEBUG is not set CONFIG_KPROBES=y @@ -1180,5 +1210,6 @@ CONFIG_KPROBES=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 5244f803203..e0eb0c712fe 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -55,20 +55,34 @@ * with the int 0x80 path. */ ENTRY(ia32_sysenter_target) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rsp,rbp swapgs movq %gs:pda_kernelstack, %rsp addq $(PDA_STACKOFFSET),%rsp sti movl %ebp,%ebp /* zero extension */ pushq $__USER32_DS + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET ss,0*/ pushq %rbp + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rsp,0 pushfq + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET rflags,0*/ movl $VSYSCALL32_SYSEXIT, %r10d + CFI_REGISTER rip,r10 pushq $__USER32_CS + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET cs,0*/ movl %eax, %eax pushq %r10 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip,0 pushq %rax + CFI_ADJUST_CFA_OFFSET 8 cld SAVE_ARGS 0,0,1 /* no need to do an access_ok check here because rbp has been @@ -79,6 +93,7 @@ ENTRY(ia32_sysenter_target) .previous GET_THREAD_INFO(%r10) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) + CFI_REMEMBER_STATE jnz sysenter_tracesys sysenter_do_call: cmpl $(IA32_NR_syscalls),%eax @@ -94,14 +109,20 @@ sysenter_do_call: andl $~0x200,EFLAGS-R11(%rsp) RESTORE_ARGS 1,24,1,1,1,1 popfq + CFI_ADJUST_CFA_OFFSET -8 + /*CFI_RESTORE rflags*/ popq %rcx /* User %esp */ + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rsp,rcx movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */ + CFI_REGISTER rip,rdx swapgs sti /* sti only takes effect after the next instruction */ /* sysexit */ .byte 0xf, 0x35 sysenter_tracesys: + CFI_RESTORE_STATE SAVE_REST CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ @@ -140,21 +161,28 @@ sysenter_tracesys: * with the int 0x80 path. */ ENTRY(ia32_cstar_target) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rip,rcx + /*CFI_REGISTER rflags,r11*/ swapgs movl %esp,%r8d + CFI_REGISTER rsp,r8 movq %gs:pda_kernelstack,%rsp sti SAVE_ARGS 8,1,1 movl %eax,%eax /* zero extension */ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rip,RIP-ARGOFFSET movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */ movl %ebp,%ecx movq $__USER32_CS,CS-ARGOFFSET(%rsp) movq $__USER32_DS,SS-ARGOFFSET(%rsp) movq %r11,EFLAGS-ARGOFFSET(%rsp) + /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ movq %r8,RSP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rsp,RSP-ARGOFFSET /* no need to do an access_ok check here because r8 has been 32bit zero extended */ /* hardware stack frame is complete now */ @@ -164,6 +192,7 @@ ENTRY(ia32_cstar_target) .previous GET_THREAD_INFO(%r10) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) + CFI_REMEMBER_STATE jnz cstar_tracesys cstar_do_call: cmpl $IA32_NR_syscalls,%eax @@ -177,12 +206,16 @@ cstar_do_call: jnz int_ret_from_sys_call RESTORE_ARGS 1,-ARG_SKIP,1,1,1 movl RIP-ARGOFFSET(%rsp),%ecx + CFI_REGISTER rip,rcx movl EFLAGS-ARGOFFSET(%rsp),%r11d + /*CFI_REGISTER rflags,r11*/ movl RSP-ARGOFFSET(%rsp),%esp + CFI_RESTORE rsp swapgs sysretl cstar_tracesys: + CFI_RESTORE_STATE SAVE_REST CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ @@ -226,11 +259,18 @@ ia32_badarg: */ ENTRY(ia32_syscall) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-RIP + /*CFI_REL_OFFSET ss,SS-RIP*/ + CFI_REL_OFFSET rsp,RSP-RIP + /*CFI_REL_OFFSET rflags,EFLAGS-RIP*/ + /*CFI_REL_OFFSET cs,CS-RIP*/ + CFI_REL_OFFSET rip,RIP-RIP swapgs sti movl %eax,%eax pushq %rax + CFI_ADJUST_CFA_OFFSET 8 cld /* note the registers are not zero extended to the sf. this could be a problem. */ @@ -278,6 +318,8 @@ quiet_ni_syscall: jmp ia32_ptregs_common .endm + CFI_STARTPROC + PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx @@ -290,8 +332,9 @@ quiet_ni_syscall: PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx ENTRY(ia32_ptregs_common) - CFI_STARTPROC popq %r11 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST call *%rax RESTORE_REST diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 04d80406ce4..5389df610e7 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -751,7 +751,7 @@ sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 1579bdd0adc..bcdd0a805fe 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -46,3 +46,4 @@ microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o +msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c index 148f6f7ea31..867a0ebee17 100644 --- a/arch/x86_64/kernel/acpi/sleep.c +++ b/arch/x86_64/kernel/acpi/sleep.c @@ -34,7 +34,6 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/bootmem.h> -#include <linux/irq.h> #include <linux/acpi.h> #include <asm/mpspec.h> #include <asm/io.h> diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c index c9a6b812e92..962ad4823b6 100644 --- a/arch/x86_64/kernel/aperture.c +++ b/arch/x86_64/kernel/aperture.c @@ -245,6 +245,8 @@ void __init iommu_hole_init(void) if (aper_alloc) { /* Got the aperture from the AGP bridge */ + } else if (swiotlb && !valid_agp) { + /* Do nothing */ } else if ((!no_iommu && end_pfn >= 0xffffffff>>PAGE_SHIFT) || force_iommu || valid_agp || diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 375d369570c..b6e7715d877 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/smp_lock.h> @@ -109,11 +108,8 @@ void clear_local_APIC(void) if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); v = GET_APIC_VERSION(apic_read(APIC_LVR)); - if (APIC_INTEGRATED(v)) { /* !82489DX */ - if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - } + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); } void __init connect_bsp_APIC(void) @@ -316,8 +312,6 @@ void __init init_bsp_APIC(void) */ apic_write_around(APIC_LVT0, APIC_DM_EXTINT); value = APIC_DM_NMI; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); } @@ -325,14 +319,6 @@ void __cpuinit setup_local_APIC (void) { unsigned int value, ver, maxlvt; - /* Pound the ESR really hard over the head with a big hammer - mbligh */ - if (esr_disable) { - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - } - value = apic_read(APIC_LVR); ver = GET_APIC_VERSION(value); @@ -430,15 +416,11 @@ void __cpuinit setup_local_APIC (void) value = APIC_DM_NMI; else value = APIC_DM_NMI | APIC_LVT_MASKED; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); - if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ + { unsigned oldvalue; maxlvt = get_maxlvt(); - if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); oldvalue = apic_read(APIC_ESR); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); @@ -452,17 +434,6 @@ void __cpuinit setup_local_APIC (void) apic_printk(APIC_VERBOSE, "ESR value after enabling vector: %08x, after %08x\n", oldvalue, value); - } else { - if (esr_disable) - /* - * Something untraceble is creating bad interrupts on - * secondary quads ... for the moment, just leave the - * ESR disabled - we can't do anything useful with the - * errors anyway - mbligh - */ - apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n"); - else - apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n"); } nmi_watchdog_default(); @@ -650,8 +621,7 @@ void __init init_apic_mappings(void) * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ - if (boot_cpu_id == -1U) - boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); #ifdef CONFIG_X86_IO_APIC { @@ -693,8 +663,6 @@ static void __setup_APIC_LVTT(unsigned int clocks) ver = GET_APIC_VERSION(apic_read(APIC_LVR)); lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - if (!APIC_INTEGRATED(ver)) - lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); apic_write_around(APIC_LVTT, lvtt_value); /* @@ -1081,7 +1049,7 @@ int __init APIC_init_uniprocessor (void) connect_bsp_APIC(); - phys_cpu_present_map = physid_mask_of_physid(0); + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id); apic_write_around(APIC_ID, boot_cpu_id); setup_local_APIC(); diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c index 35b4c3fcbb3..aaa6d383351 100644 --- a/arch/x86_64/kernel/asm-offsets.c +++ b/arch/x86_64/kernel/asm-offsets.c @@ -39,7 +39,6 @@ int main(void) ENTRY(kernelstack); ENTRY(oldrsp); ENTRY(pcurrent); - ENTRY(irqrsp); ENTRY(irqcount); ENTRY(cpunumber); ENTRY(irqstackptr); diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c index d7fa4248501..535e0446607 100644 --- a/arch/x86_64/kernel/crash.c +++ b/arch/x86_64/kernel/crash.c @@ -11,7 +11,6 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/smp.h> -#include <linux/irq.h> #include <linux/reboot.h> #include <linux/kexec.h> diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index bb0ae18ec02..eb7929eea7b 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -131,7 +131,7 @@ void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned lon if (ei->type != E820_RAM || ei->addr+ei->size <= start || - ei->addr > end) + ei->addr >= end) continue; addr = round_up(ei->addr, PAGE_SIZE); diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c index 9631c747c5e..9cd968dd0f5 100644 --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -5,6 +5,7 @@ #include <linux/tty.h> #include <asm/io.h> #include <asm/processor.h> +#include <asm/fcntl.h> /* Simple VGA output */ @@ -158,6 +159,47 @@ static struct console early_serial_console = { .index = -1, }; +/* Console interface to a host file on AMD's SimNow! */ + +static int simnow_fd; + +enum { + MAGIC1 = 0xBACCD00A, + MAGIC2 = 0xCA110000, + XOPEN = 5, + XWRITE = 4, +}; + +static noinline long simnow(long cmd, long a, long b, long c) +{ + long ret; + asm volatile("cpuid" : + "=a" (ret) : + "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); + return ret; +} + +void __init simnow_init(char *str) +{ + char *fn = "klog"; + if (*str == '=') + fn = ++str; + /* error ignored */ + simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); +} + +static void simnow_write(struct console *con, const char *s, unsigned n) +{ + simnow(XWRITE, simnow_fd, (unsigned long)s, n); +} + +static struct console simnow_console = { + .name = "simnow", + .write = simnow_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + /* Direct interface for emergencies */ struct console *early_console = &early_vga_console; static int early_console_initialized = 0; @@ -205,6 +247,10 @@ int __init setup_early_printk(char *opt) max_xpos = SCREEN_INFO.orig_video_cols; max_ypos = SCREEN_INFO.orig_video_lines; early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { + simnow_init(buf + 6); + early_console = &simnow_console; + keep_early = 1; } early_console_initialized = 1; register_console(early_console); diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 3620508c8bd..7937971d185 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -79,16 +79,19 @@ xorl %eax, %eax pushq %rax /* ss */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET ss,0*/ pushq %rax /* rsp */ CFI_ADJUST_CFA_OFFSET 8 - CFI_OFFSET rip,0 + CFI_REL_OFFSET rsp,0 pushq $(1<<9) /* eflags - interrupts on */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET rflags,0*/ pushq $__KERNEL_CS /* cs */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET cs,0*/ pushq \child_rip /* rip */ CFI_ADJUST_CFA_OFFSET 8 - CFI_OFFSET rip,0 + CFI_REL_OFFSET rip,0 pushq %rax /* orig rax */ CFI_ADJUST_CFA_OFFSET 8 .endm @@ -98,32 +101,39 @@ CFI_ADJUST_CFA_OFFSET -(6*8) .endm - .macro CFI_DEFAULT_STACK - CFI_ADJUST_CFA_OFFSET (SS) - CFI_OFFSET r15,R15-SS - CFI_OFFSET r14,R14-SS - CFI_OFFSET r13,R13-SS - CFI_OFFSET r12,R12-SS - CFI_OFFSET rbp,RBP-SS - CFI_OFFSET rbx,RBX-SS - CFI_OFFSET r11,R11-SS - CFI_OFFSET r10,R10-SS - CFI_OFFSET r9,R9-SS - CFI_OFFSET r8,R8-SS - CFI_OFFSET rax,RAX-SS - CFI_OFFSET rcx,RCX-SS - CFI_OFFSET rdx,RDX-SS - CFI_OFFSET rsi,RSI-SS - CFI_OFFSET rdi,RDI-SS - CFI_OFFSET rsp,RSP-SS - CFI_OFFSET rip,RIP-SS + .macro CFI_DEFAULT_STACK start=1 + .if \start + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8 + .else + CFI_DEF_CFA_OFFSET SS+8 + .endif + CFI_REL_OFFSET r15,R15 + CFI_REL_OFFSET r14,R14 + CFI_REL_OFFSET r13,R13 + CFI_REL_OFFSET r12,R12 + CFI_REL_OFFSET rbp,RBP + CFI_REL_OFFSET rbx,RBX + CFI_REL_OFFSET r11,R11 + CFI_REL_OFFSET r10,R10 + CFI_REL_OFFSET r9,R9 + CFI_REL_OFFSET r8,R8 + CFI_REL_OFFSET rax,RAX + CFI_REL_OFFSET rcx,RCX + CFI_REL_OFFSET rdx,RDX + CFI_REL_OFFSET rsi,RSI + CFI_REL_OFFSET rdi,RDI + CFI_REL_OFFSET rip,RIP + /*CFI_REL_OFFSET cs,CS*/ + /*CFI_REL_OFFSET rflags,EFLAGS*/ + CFI_REL_OFFSET rsp,RSP + /*CFI_REL_OFFSET ss,SS*/ .endm /* * A newly forked process directly context switches into this. */ /* rdi: prev */ ENTRY(ret_from_fork) - CFI_STARTPROC CFI_DEFAULT_STACK call schedule_tail GET_THREAD_INFO(%rcx) @@ -172,16 +182,21 @@ rff_trace: */ ENTRY(system_call) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rip,rcx + /*CFI_REGISTER rflags,r11*/ swapgs movq %rsp,%gs:pda_oldrsp movq %gs:pda_kernelstack,%rsp sti SAVE_ARGS 8,1 movq %rax,ORIG_RAX-ARGOFFSET(%rsp) - movq %rcx,RIP-ARGOFFSET(%rsp) + movq %rcx,RIP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rip,RIP-ARGOFFSET GET_THREAD_INFO(%rcx) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx) + CFI_REMEMBER_STATE jnz tracesys cmpq $__NR_syscall_max,%rax ja badsys @@ -201,9 +216,12 @@ sysret_check: cli movl threadinfo_flags(%rcx),%edx andl %edi,%edx + CFI_REMEMBER_STATE jnz sysret_careful movq RIP-ARGOFFSET(%rsp),%rcx + CFI_REGISTER rip,rcx RESTORE_ARGS 0,-ARG_SKIP,1 + /*CFI_REGISTER rflags,r11*/ movq %gs:pda_oldrsp,%rsp swapgs sysretq @@ -211,12 +229,15 @@ sysret_check: /* Handle reschedules */ /* edx: work, edi: workmask */ sysret_careful: + CFI_RESTORE_STATE bt $TIF_NEED_RESCHED,%edx jnc sysret_signal sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 jmp sysret_check /* Handle a signal */ @@ -234,8 +255,13 @@ sysret_signal: 1: movl $_TIF_NEED_RESCHED,%edi jmp sysret_check +badsys: + movq $-ENOSYS,RAX-ARGOFFSET(%rsp) + jmp ret_from_sys_call + /* Do syscall tracing */ tracesys: + CFI_RESTORE_STATE SAVE_REST movq $-ENOSYS,RAX(%rsp) FIXUP_TOP_OF_STACK %rdi @@ -254,16 +280,29 @@ tracesys: RESTORE_TOP_OF_STACK %rbx RESTORE_REST jmp ret_from_sys_call + CFI_ENDPROC -badsys: - movq $-ENOSYS,RAX-ARGOFFSET(%rsp) - jmp ret_from_sys_call - /* * Syscall return path ending with IRET. * Has correct top of stack, but partial stack frame. */ -ENTRY(int_ret_from_sys_call) +ENTRY(int_ret_from_sys_call) + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-ARGOFFSET + /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/ + CFI_REL_OFFSET rsp,RSP-ARGOFFSET + /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ + /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/ + CFI_REL_OFFSET rip,RIP-ARGOFFSET + CFI_REL_OFFSET rdx,RDX-ARGOFFSET + CFI_REL_OFFSET rcx,RCX-ARGOFFSET + CFI_REL_OFFSET rax,RAX-ARGOFFSET + CFI_REL_OFFSET rdi,RDI-ARGOFFSET + CFI_REL_OFFSET rsi,RSI-ARGOFFSET + CFI_REL_OFFSET r8,R8-ARGOFFSET + CFI_REL_OFFSET r9,R9-ARGOFFSET + CFI_REL_OFFSET r10,R10-ARGOFFSET + CFI_REL_OFFSET r11,R11-ARGOFFSET cli testl $3,CS-ARGOFFSET(%rsp) je retint_restore_args @@ -284,8 +323,10 @@ int_careful: jnc int_very_careful sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 cli jmp int_with_check @@ -297,9 +338,11 @@ int_very_careful: testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx jz int_signal pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 leaq 8(%rsp),%rdi # &ptregs -> arg1 call syscall_trace_leave popq %rdi + CFI_ADJUST_CFA_OFFSET -8 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi cli jmp int_restore_rest @@ -329,6 +372,8 @@ int_restore_rest: jmp ptregscall_common .endm + CFI_STARTPROC + PTREGSCALL stub_clone, sys_clone, %r8 PTREGSCALL stub_fork, sys_fork, %rdi PTREGSCALL stub_vfork, sys_vfork, %rdi @@ -337,40 +382,49 @@ int_restore_rest: PTREGSCALL stub_iopl, sys_iopl, %rsi ENTRY(ptregscall_common) - CFI_STARTPROC popq %r11 - CFI_ADJUST_CFA_OFFSET -8 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST movq %r11, %r15 + CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call *%rax RESTORE_TOP_OF_STACK %r11 movq %r15, %r11 + CFI_REGISTER rip, r11 RESTORE_REST pushq %r11 - CFI_ADJUST_CFA_OFFSET 8 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip, 0 ret CFI_ENDPROC ENTRY(stub_execve) CFI_STARTPROC popq %r11 - CFI_ADJUST_CFA_OFFSET -8 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST movq %r11, %r15 + CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call sys_execve GET_THREAD_INFO(%rcx) bt $TIF_IA32,threadinfo_flags(%rcx) + CFI_REMEMBER_STATE jc exec_32bit RESTORE_TOP_OF_STACK %r11 movq %r15, %r11 + CFI_REGISTER rip, r11 RESTORE_REST - push %r11 + pushq %r11 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip, 0 ret exec_32bit: - CFI_ADJUST_CFA_OFFSET REST_SKIP + CFI_RESTORE_STATE movq %rax,RAX(%rsp) RESTORE_REST jmp int_ret_from_sys_call @@ -382,7 +436,8 @@ exec_32bit: */ ENTRY(stub_rt_sigreturn) CFI_STARTPROC - addq $8, %rsp + addq $8, %rsp + CFI_ADJUST_CFA_OFFSET -8 SAVE_REST movq %rsp,%rdi FIXUP_TOP_OF_STACK %r11 @@ -392,6 +447,25 @@ ENTRY(stub_rt_sigreturn) jmp int_ret_from_sys_call CFI_ENDPROC +/* + * initial frame state for interrupts and exceptions + */ + .macro _frame ref + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-\ref + /*CFI_REL_OFFSET ss,SS-\ref*/ + CFI_REL_OFFSET rsp,RSP-\ref + /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/ + /*CFI_REL_OFFSET cs,CS-\ref*/ + CFI_REL_OFFSET rip,RIP-\ref + .endm + +/* initial frame state for interrupts (and exceptions without error code) */ +#define INTR_FRAME _frame RIP +/* initial frame state for exceptions with error code (and interrupts with + vector already pushed) */ +#define XCPT_FRAME _frame ORIG_RAX + /* * Interrupt entry/exit. * @@ -402,10 +476,6 @@ ENTRY(stub_rt_sigreturn) /* 0(%rsp): interrupt number */ .macro interrupt func - CFI_STARTPROC simple - CFI_DEF_CFA rsp,(SS-RDI) - CFI_REL_OFFSET rsp,(RSP-ORIG_RAX) - CFI_REL_OFFSET rip,(RIP-ORIG_RAX) cld #ifdef CONFIG_DEBUG_INFO SAVE_ALL @@ -425,23 +495,27 @@ ENTRY(stub_rt_sigreturn) swapgs 1: incl %gs:pda_irqcount # RED-PEN should check preempt count movq %gs:pda_irqstackptr,%rax - cmoveq %rax,%rsp + cmoveq %rax,%rsp /*todo This needs CFI annotation! */ pushq %rdi # save old stack + CFI_ADJUST_CFA_OFFSET 8 call \func .endm ENTRY(common_interrupt) + XCPT_FRAME interrupt do_IRQ /* 0(%rsp): oldrsp-ARGOFFSET */ -ret_from_intr: +ret_from_intr: popq %rdi + CFI_ADJUST_CFA_OFFSET -8 cli decl %gs:pda_irqcount #ifdef CONFIG_DEBUG_INFO movq RBP(%rdi),%rbp + CFI_DEF_CFA_REGISTER rsp #endif - leaq ARGOFFSET(%rdi),%rsp -exit_intr: + leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */ +exit_intr: GET_THREAD_INFO(%rcx) testl $3,CS-ARGOFFSET(%rsp) je retint_kernel @@ -453,9 +527,10 @@ exit_intr: */ retint_with_reschedule: movl $_TIF_WORK_MASK,%edi -retint_check: +retint_check: movl threadinfo_flags(%rcx),%edx andl %edi,%edx + CFI_REMEMBER_STATE jnz retint_careful retint_swapgs: swapgs @@ -476,14 +551,17 @@ bad_iret: jmp do_exit .previous - /* edi: workmask, edx: work */ + /* edi: workmask, edx: work */ retint_careful: + CFI_RESTORE_STATE bt $TIF_NEED_RESCHED,%edx jnc retint_signal sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 GET_THREAD_INFO(%rcx) cli jmp retint_check @@ -523,7 +601,9 @@ retint_kernel: * APIC interrupts. */ .macro apicinterrupt num,func + INTR_FRAME pushq $\num-256 + CFI_ADJUST_CFA_OFFSET 8 interrupt \func jmp ret_from_intr CFI_ENDPROC @@ -536,8 +616,19 @@ ENTRY(thermal_interrupt) ENTRY(reschedule_interrupt) apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt -ENTRY(invalidate_interrupt) - apicinterrupt INVALIDATE_TLB_VECTOR,smp_invalidate_interrupt + .macro INVALIDATE_ENTRY num +ENTRY(invalidate_interrupt\num) + apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt + .endm + + INVALIDATE_ENTRY 0 + INVALIDATE_ENTRY 1 + INVALIDATE_ENTRY 2 + INVALIDATE_ENTRY 3 + INVALIDATE_ENTRY 4 + INVALIDATE_ENTRY 5 + INVALIDATE_ENTRY 6 + INVALIDATE_ENTRY 7 ENTRY(call_function_interrupt) apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt @@ -558,16 +649,23 @@ ENTRY(spurious_interrupt) * Exception entry points. */ .macro zeroentry sym + INTR_FRAME pushq $0 /* push error code/oldrax */ + CFI_ADJUST_CFA_OFFSET 8 pushq %rax /* push real oldrax to the rdi slot */ + CFI_ADJUST_CFA_OFFSET 8 leaq \sym(%rip),%rax jmp error_entry + CFI_ENDPROC .endm .macro errorentry sym + XCPT_FRAME pushq %rax + CFI_ADJUST_CFA_OFFSET 8 leaq \sym(%rip),%rax jmp error_entry + CFI_ENDPROC .endm /* error code is on the stack already */ @@ -594,10 +692,7 @@ ENTRY(spurious_interrupt) * and the exception handler in %rax. */ ENTRY(error_entry) - CFI_STARTPROC simple - CFI_DEF_CFA rsp,(SS-RDI) - CFI_REL_OFFSET rsp,(RSP-RDI) - CFI_REL_OFFSET rip,(RIP-RDI) + _frame RDI /* rdi slot contains rax, oldrax contains error code */ cld subq $14*8,%rsp @@ -679,7 +774,9 @@ error_kernelspace: /* Reload gs selector with exception handling */ /* edi: new selector */ ENTRY(load_gs_index) + CFI_STARTPROC pushf + CFI_ADJUST_CFA_OFFSET 8 cli swapgs gs_change: @@ -687,7 +784,9 @@ gs_change: 2: mfence /* workaround */ swapgs popf + CFI_ADJUST_CFA_OFFSET -8 ret + CFI_ENDPROC .section __ex_table,"a" .align 8 @@ -799,7 +898,7 @@ ENTRY(device_not_available) /* runs on exception stack */ KPROBE_ENTRY(debug) - CFI_STARTPROC + INTR_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_debug @@ -809,9 +908,9 @@ KPROBE_ENTRY(debug) /* runs on exception stack */ ENTRY(nmi) - CFI_STARTPROC + INTR_FRAME pushq $-1 - CFI_ADJUST_CFA_OFFSET 8 + CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_nmi /* * "Paranoid" exit path from exception stack. @@ -877,7 +976,7 @@ ENTRY(reserved) /* runs on exception stack */ ENTRY(double_fault) - CFI_STARTPROC + XCPT_FRAME paranoidentry do_double_fault jmp paranoid_exit CFI_ENDPROC @@ -890,7 +989,7 @@ ENTRY(segment_not_present) /* runs on exception stack */ ENTRY(stack_segment) - CFI_STARTPROC + XCPT_FRAME paranoidentry do_stack_segment jmp paranoid_exit CFI_ENDPROC @@ -911,7 +1010,7 @@ ENTRY(spurious_interrupt_bug) #ifdef CONFIG_X86_MCE /* runs on exception stack */ ENTRY(machine_check) - CFI_STARTPROC + INTR_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_machine_check @@ -923,14 +1022,19 @@ ENTRY(call_debug) zeroentry do_call_debug ENTRY(call_softirq) + CFI_STARTPROC movq %gs:pda_irqstackptr,%rax pushq %r15 + CFI_ADJUST_CFA_OFFSET 8 movq %rsp,%r15 + CFI_DEF_CFA_REGISTER r15 incl %gs:pda_irqcount cmove %rax,%rsp call __do_softirq movq %r15,%rsp + CFI_DEF_CFA_REGISTER rsp decl %gs:pda_irqcount popq %r15 + CFI_ADJUST_CFA_OFFSET -8 ret - + CFI_ENDPROC diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index b1c144f7314..7a64ea18178 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -45,7 +45,7 @@ void __init clustered_apic_check(void) u8 clusters, max_cluster; u8 id; u8 cluster_cnt[NUM_APIC_CLUSTERS]; - int num_cpus = 0; + int max_apic = 0; #if defined(CONFIG_ACPI) /* @@ -64,14 +64,15 @@ void __init clustered_apic_check(void) id = bios_cpu_apicid[i]; if (id == BAD_APICID) continue; - num_cpus++; + if (id > max_apic) + max_apic = id; cluster_cnt[APIC_CLUSTERID(id)]++; } /* Don't use clustered mode on AMD platforms. */ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { genapic = &apic_physflat; -#ifndef CONFIG_CPU_HOTPLUG +#ifndef CONFIG_HOTPLUG_CPU /* In the CPU hotplug case we cannot use broadcast mode because that opens a race when a CPU is removed. Stay at physflat mode in this case. @@ -79,7 +80,7 @@ void __init clustered_apic_check(void) we have ACPI platform support for CPU hotplug we should detect hotplug capablity from ACPI tables and only do this when really needed. -AK */ - if (num_cpus <= 8) + if (max_apic <= 8) genapic = &apic_flat; #endif goto print; @@ -103,9 +104,14 @@ void __init clustered_apic_check(void) * (We don't use lowest priority delivery + HW APIC IRQ steering, so * can ignore the clustered logical case and go straight to physical.) */ - if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) + if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) { +#ifdef CONFIG_HOTPLUG_CPU + /* Don't use APIC shortcuts in CPU hotplug to avoid races */ + genapic = &apic_physflat; +#else genapic = &apic_flat; - else +#endif + } else genapic = &apic_cluster; print: diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c index f6523dd1bc0..a472d62f899 100644 --- a/arch/x86_64/kernel/genapic_cluster.c +++ b/arch/x86_64/kernel/genapic_cluster.c @@ -51,10 +51,10 @@ static void cluster_init_apic_ldr(void) count = 3; id = my_cluster | (1UL << count); x86_cpu_to_log_apicid[smp_processor_id()] = id; - apic_write_around(APIC_DFR, APIC_DFR_CLUSTER); + apic_write(APIC_DFR, APIC_DFR_CLUSTER); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); - apic_write_around(APIC_LDR, val); + apic_write(APIC_LDR, val); } /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index 6d57da96bf8..9da3edb799e 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -38,10 +38,10 @@ static void flat_init_apic_ldr(void) num = smp_processor_id(); id = 1UL << num; x86_cpu_to_log_apicid[num] = id; - apic_write_around(APIC_DFR, APIC_DFR_FLAT); + apic_write(APIC_DFR, APIC_DFR_FLAT); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); - apic_write_around(APIC_LDR, val); + apic_write(APIC_LDR, val); } static void flat_send_IPI_mask(cpumask_t cpumask, int vector) @@ -62,7 +62,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) * prepare target chip field */ cfg = __prepare_ICR2(mask); - apic_write_around(APIC_ICR2, cfg); + apic_write(APIC_ICR2, cfg); /* * program the ICR @@ -72,7 +72,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); local_irq_restore(flags); } @@ -177,9 +177,9 @@ static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask) struct genapic apic_physflat = { .name = "physical flat", - .int_delivery_mode = dest_LowestPrio, + .int_delivery_mode = dest_Fixed, .int_dest_mode = (APIC_DEST_PHYSICAL != 0), - .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_LOWEST, + .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED, .target_cpus = physflat_target_cpus, .apic_id_registered = flat_apic_id_registered, .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/ diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S index 98ff5eb32b9..4592bf21fca 100644 --- a/arch/x86_64/kernel/head.S +++ b/arch/x86_64/kernel/head.S @@ -270,7 +270,7 @@ ENTRY(level3_kernel_pgt) .org 0x4000 ENTRY(level2_ident_pgt) /* 40MB for bootup. */ - .quad 0x0000000000000283 + .quad 0x0000000000000183 .quad 0x0000000000200183 .quad 0x0000000000400183 .quad 0x0000000000600183 diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index a8916909512..b2a238b5a17 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -18,15 +18,12 @@ #include <asm/atomic.h> #include <asm/system.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/hw_irq.h> #include <asm/pgtable.h> #include <asm/delay.h> #include <asm/desc.h> #include <asm/apic.h> -#include <linux/irq.h> - /* * Common place to define all x86 IRQ vectors * @@ -486,7 +483,14 @@ void spurious_interrupt(void); void error_interrupt(void); void reschedule_interrupt(void); void call_function_interrupt(void); -void invalidate_interrupt(void); +void invalidate_interrupt0(void); +void invalidate_interrupt1(void); +void invalidate_interrupt2(void); +void invalidate_interrupt3(void); +void invalidate_interrupt4(void); +void invalidate_interrupt5(void); +void invalidate_interrupt6(void); +void invalidate_interrupt7(void); void thermal_interrupt(void); void i8254_timer_resume(void); @@ -562,8 +566,15 @@ void __init init_IRQ(void) */ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); + /* IPIs for invalidation */ + set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7); /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c index c4dc9149115..e0ba5c1043f 100644 --- a/arch/x86_64/kernel/init_task.c +++ b/arch/x86_64/kernel/init_task.c @@ -44,6 +44,6 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 5f1529be123..522944a000a 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -21,7 +21,6 @@ */ #include <linux/mm.h> -#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/delay.h> @@ -45,6 +44,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ static int no_timer_check; +int disable_timer_pin_1 __initdata; + static DEFINE_SPINLOCK(ioapic_lock); /* @@ -298,6 +299,15 @@ void __init check_ioapic(void) #endif /* RED-PEN skip them on mptables too? */ return; + case PCI_VENDOR_ID_ATI: + /* All timer interrupts on atiixp + are doubled. Disable one. */ + if (disable_timer_pin_1 == 0) { + disable_timer_pin_1 = 1; + printk(KERN_INFO + "ATI board detected. Disabling timer pin 1.\n"); + } + return; } /* No multi-function device? */ @@ -1022,13 +1032,11 @@ void __apicdebuginit print_local_APIC(void * dummy) v = apic_read(APIC_TASKPRI); printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - v = apic_read(APIC_ARBPRI); - printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, - v & APIC_ARBPRI_MASK); - v = apic_read(APIC_PROCPRI); - printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); - } + v = apic_read(APIC_ARBPRI); + printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, + v & APIC_ARBPRI_MASK); + v = apic_read(APIC_PROCPRI); + printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); v = apic_read(APIC_EOI); printk(KERN_DEBUG "... APIC EOI: %08x\n", v); @@ -1048,12 +1056,8 @@ void __apicdebuginit print_local_APIC(void * dummy) printk(KERN_DEBUG "... APIC IRR field:\n"); print_APIC_bitfield(APIC_IRR); - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); - printk(KERN_DEBUG "... APIC ESR: %08x\n", v); - } + v = apic_read(APIC_ESR); + printk(KERN_DEBUG "... APIC ESR: %08x\n", v); v = apic_read(APIC_ICR); printk(KERN_DEBUG "... APIC ICR: %08x\n", v); @@ -1665,6 +1669,8 @@ static inline void check_timer(void) setup_nmi(); enable_8259A_irq(0); } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); return; } clear_IO_APIC_pin(0, pin1); diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 849a20aec7c..d6a04a8320a 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -99,7 +99,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) unsigned irq = regs->orig_rax & 0xff; irq_enter(); - BUG_ON(irq > 256); __do_IRQ(irq, regs); irq_exit(); diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 8aa56736cde..969365c0771 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/cpu.h> #include <linux/percpu.h> +#include <linux/ctype.h> #include <asm/processor.h> #include <asm/msr.h> #include <asm/mce.h> @@ -56,15 +57,19 @@ void mce_log(struct mce *mce) smp_wmb(); for (;;) { entry = rcu_dereference(mcelog.next); - /* When the buffer fills up discard new entries. Assume - that the earlier errors are the more interesting. */ - if (entry >= MCE_LOG_LEN) { - set_bit(MCE_OVERFLOW, &mcelog.flags); - return; + for (;;) { + /* When the buffer fills up discard new entries. Assume + that the earlier errors are the more interesting. */ + if (entry >= MCE_LOG_LEN) { + set_bit(MCE_OVERFLOW, &mcelog.flags); + return; + } + /* Old left over entry. Skip. */ + if (mcelog.entry[entry].finished) { + entry++; + continue; + } } - /* Old left over entry. Skip. */ - if (mcelog.entry[entry].finished) - continue; smp_rmb(); next = entry + 1; if (cmpxchg(&mcelog.next, entry, next) == entry) @@ -404,9 +409,15 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff } err = 0; - for (i = 0; i < next; i++) { - if (!mcelog.entry[i].finished) - continue; + for (i = 0; i < next; i++) { + unsigned long start = jiffies; + while (!mcelog.entry[i].finished) { + if (!time_before(jiffies, start + 2)) { + memset(mcelog.entry + i,0, sizeof(struct mce)); + continue; + } + cpu_relax(); + } smp_rmb(); err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); buf += sizeof(struct mce); @@ -479,6 +490,7 @@ static int __init mcheck_disable(char *str) /* mce=off disables machine check. Note you can reenable it later using sysfs. + mce=TOLERANCELEVEL (number, see above) mce=bootlog Log MCEs from before booting. Disabled by default to work around buggy BIOS that leave bogus MCEs. */ static int __init mcheck_enable(char *str) @@ -489,6 +501,8 @@ static int __init mcheck_enable(char *str) mce_dont_init = 1; else if (!strcmp(str, "bootlog")) mce_bootlog = 1; + else if (isdigit(str[0])) + get_option(&str, &tolerant); else printk("mce= argument %s ignored. Please use /sys", str); return 0; @@ -501,10 +515,12 @@ __setup("mce", mcheck_enable); * Sysfs support */ -/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */ +/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. + Only one CPU is active at this time, the others get readded later using + CPU hotplug. */ static int mce_resume(struct sys_device *dev) { - on_each_cpu(mce_init, NULL, 1, 1); + mce_init(NULL); return 0; } diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 8d8ed6ae1d0..f16d38d09da 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -14,7 +14,6 @@ */ #include <linux/mm.h> -#include <linux/irq.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/config.h> @@ -46,8 +45,6 @@ int acpi_found_madt; int apic_version [MAX_APICS]; unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; -unsigned char pci_bus_to_node [256]; -EXPORT_SYMBOL(pci_bus_to_node); static int mp_current_pci_id = 0; /* I/O APIC entries */ @@ -705,7 +702,7 @@ void __init mp_register_lapic ( processor.mpc_type = MP_PROCESSOR; processor.mpc_apicid = id; - processor.mpc_apicver = 0x10; /* TBD: lapic version */ + processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c deleted file mode 100644 index 598953ab015..00000000000 --- a/arch/x86_64/kernel/msr.c +++ /dev/null @@ -1,279 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2000 H. Peter Anvin - 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 as published by - * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, - * USA; either version 2 of the License, or (at your option) any later - * version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * msr.c - * - * x86 MSR access device - * - * This device is accessed by lseek() to the appropriate register number - * and then read/write in chunks of 8 bytes. A larger size means multiple - * reads or writes of the same register. - * - * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on - * an SMP box will direct the access to CPU %d. - */ - -#include <linux/module.h> -#include <linux/config.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/major.h> -#include <linux/fs.h> - -#include <asm/processor.h> -#include <asm/msr.h> -#include <asm/uaccess.h> -#include <asm/system.h> - -/* Note: "err" is handled in a funny way below. Otherwise one version - of gcc or another breaks. */ - -static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) -{ - int err; - - asm volatile ("1: wrmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" " .quad 1b,3b\n" ".previous":"=&bDS" (err) - :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0)); - - return err; -} - -static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) -{ - int err; - - asm volatile ("1: rdmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 1b,3b\n" - ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx) - :"c"(reg), "i"(-EIO), "0"(0)); - - return err; -} - -#ifdef CONFIG_SMP - -struct msr_command { - int cpu; - int err; - u32 reg; - u32 data[2]; -}; - -static void msr_smp_wrmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - if (cmd->cpu == smp_processor_id()) - cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); -} - -static void msr_smp_rdmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - if (cmd->cpu == smp_processor_id()) - cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); -} - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = wrmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - cmd.data[0] = eax; - cmd.data[1] = edx; - - smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = rdmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - - smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); - - *eax = cmd.data[0]; - *edx = cmd.data[1]; - - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -#else /* ! CONFIG_SMP */ - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - return wrmsr_eio(reg, eax, edx); -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) -{ - return rdmsr_eio(reg, eax, edx); -} - -#endif /* ! CONFIG_SMP */ - -static loff_t msr_seek(struct file *file, loff_t offset, int orig) -{ - loff_t ret = -EINVAL; - - lock_kernel(); - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - } - unlock_kernel(); - return ret; -} - -static ssize_t msr_read(struct file *file, char __user * buf, - size_t count, loff_t * ppos) -{ - u32 __user *tmp = (u32 __user *) buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if (count % 8) - return -EINVAL; /* Invalid chunk size */ - - for (rv = 0; count; count -= 8) { - err = do_rdmsr(cpu, reg, &data[0], &data[1]); - if (err) - return err; - if (copy_to_user(tmp, &data, 8)) - return -EFAULT; - tmp += 2; - } - - return ((char __user *)tmp) - buf; -} - -static ssize_t msr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - const u32 __user *tmp = (const u32 __user *)buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if (count % 8) - return -EINVAL; /* Invalid chunk size */ - - for (rv = 0; count; count -= 8) { - if (copy_from_user(&data, tmp, 8)) - return -EFAULT; - err = do_wrmsr(cpu, reg, data[0], data[1]); - if (err) - return err; - tmp += 2; - } - - return ((char __user *)tmp) - buf; -} - -static int msr_open(struct inode *inode, struct file *file) -{ - unsigned int cpu = iminor(file->f_dentry->d_inode); - struct cpuinfo_x86 *c = &(cpu_data)[cpu]; - - if (cpu >= NR_CPUS || !cpu_online(cpu)) - return -ENXIO; /* No such CPU */ - if (!cpu_has(c, X86_FEATURE_MSR)) - return -EIO; /* MSR not supported */ - - return 0; -} - -/* - * File operations we support - */ -static struct file_operations msr_fops = { - .owner = THIS_MODULE, - .llseek = msr_seek, - .read = msr_read, - .write = msr_write, - .open = msr_open, -}; - -static int __init msr_init(void) -{ - if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { - printk(KERN_ERR "msr: unable to get major %d for msr\n", - MSR_MAJOR); - return -EBUSY; - } - - return 0; -} - -static void __exit msr_exit(void) -{ - unregister_chrdev(MSR_MAJOR, "cpu/msr"); -} - -module_init(msr_init); -module_exit(msr_exit) - -MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); -MODULE_DESCRIPTION("x86 generic MSR driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index caf164959e1..4388b8a5bae 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -14,7 +14,6 @@ #include <linux/config.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/smp_lock.h> @@ -488,8 +487,8 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) == NOTIFY_STOP) { local_set(&__get_cpu_var(alert_counter), 0); return; - } - die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs); + } + die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs); } } else { __get_cpu_var(last_irq_sum) = sum; diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index 57f35c68aa3..cf0a0315d58 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -191,11 +191,9 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) { struct page *page; int node; - if (dev->bus == &pci_bus_type) { - cpumask_t mask; - mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); - node = cpu_to_node(first_cpu(mask)); - } else + if (dev->bus == &pci_bus_type) + node = pcibus_to_node(to_pci_dev(dev)->bus); + else node = numa_node_id(); page = alloc_pages_node(node, gfp, order); return page ? page_address(page) : NULL; diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 8661f82ac70..b5a89c0bdf5 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -32,7 +32,6 @@ #include <linux/a.out.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/irq.h> #include <linux/ptrace.h> #include <linux/utsname.h> #include <linux/random.h> @@ -123,6 +122,7 @@ static void poll_idle (void) : : "i" (_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); + clear_thread_flag(TIF_POLLING_NRFLAG); } else { set_need_resched(); } @@ -271,8 +271,11 @@ void __show_regs(struct pt_regs * regs) printk("\n"); print_modules(); - printk("Pid: %d, comm: %.20s %s %s\n", - current->pid, current->comm, print_tainted(), system_utsname.release); + printk("Pid: %d, comm: %.20s %s %s %.*s\n", + current->pid, current->comm, print_tainted(), + system_utsname.release, + (int)strcspn(system_utsname.version, " "), + system_utsname.version); printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); printk_address(regs->rip); printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags); @@ -483,33 +486,6 @@ out: } /* - * This function selects if the context switch from prev to next - * has to tweak the TSC disable bit in the cr4. - */ -static inline void disable_tsc(struct task_struct *prev_p, - struct task_struct *next_p) -{ - struct thread_info *prev, *next; - - /* - * gcc should eliminate the ->thread_info dereference if - * has_secure_computing returns 0 at compile time (SECCOMP=n). - */ - prev = prev_p->thread_info; - next = next_p->thread_info; - - if (has_secure_computing(prev) || has_secure_computing(next)) { - /* slow path here */ - if (has_secure_computing(prev) && - !has_secure_computing(next)) { - write_cr4(read_cr4() & ~X86_CR4_TSD); - } else if (!has_secure_computing(prev) && - has_secure_computing(next)) - write_cr4(read_cr4() | X86_CR4_TSD); - } -} - -/* * This special macro can be used to load a debugging register */ #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) @@ -627,8 +603,6 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * } } - disable_tsc(prev_p, next_p); - return prev_p; } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 9aec524be3e..351d8d64c2f 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -336,6 +336,11 @@ static __init void parse_cmdline_early (char ** cmdline_p) #endif #endif + if (!memcmp(from, "disable_timer_pin_1", 19)) + disable_timer_pin_1 = 1; + if (!memcmp(from, "enable_timer_pin_1", 18)) + disable_timer_pin_1 = -1; + if (!memcmp(from, "nolapic", 7) || !memcmp(from, "disableapic", 11)) disable_apic = 1; @@ -755,6 +760,24 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c) } } +#ifdef CONFIG_NUMA +static int nearby_node(int apicid) +{ + int i; + for (i = apicid - 1; i >= 0; i--) { + int node = apicid_to_node[i]; + if (node != NUMA_NO_NODE && node_online(node)) + return node; + } + for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { + int node = apicid_to_node[i]; + if (node != NUMA_NO_NODE && node_online(node)) + return node; + } + return first_node(node_online_map); /* Shouldn't happen */ +} +#endif + /* * On a AMD dual core setup the lower bits of the APIC id distingush the cores. * Assumes number of cores is a power of two. @@ -763,8 +786,11 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP int cpu = smp_processor_id(); - int node = 0; unsigned bits; +#ifdef CONFIG_NUMA + int node = 0; + unsigned apicid = phys_proc_id[cpu]; +#endif bits = 0; while ((1 << bits) < c->x86_num_cores) @@ -776,20 +802,32 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) phys_proc_id[cpu] >>= bits; #ifdef CONFIG_NUMA - /* When an ACPI SRAT table is available use the mappings from SRAT - instead. */ - if (acpi_numa <= 0) { - node = phys_proc_id[cpu]; - if (!node_online(node)) - node = first_node(node_online_map); - cpu_to_node[cpu] = node; - } else { - node = cpu_to_node[cpu]; - } + node = phys_proc_id[cpu]; + if (apicid_to_node[apicid] != NUMA_NO_NODE) + node = apicid_to_node[apicid]; + if (!node_online(node)) { + /* Two possibilities here: + - The CPU is missing memory and no node was created. + In that case try picking one from a nearby CPU + - The APIC IDs differ from the HyperTransport node IDs + which the K8 northbridge parsing fills in. + Assume they are all increased by a constant offset, + but in the same order as the HT nodeids. + If that doesn't result in a usable node fall back to the + path for the previous case. */ + int ht_nodeid = apicid - (phys_proc_id[0] << bits); + if (ht_nodeid >= 0 && + apicid_to_node[ht_nodeid] != NUMA_NO_NODE) + node = apicid_to_node[ht_nodeid]; + /* Pick a nearby node */ + if (!node_online(node)) + node = nearby_node(apicid); + } + cpu_to_node[cpu] = node; + + printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", + cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif - - printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", - cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif } @@ -909,6 +947,25 @@ static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c) return 1; } +static void srat_detect_node(void) +{ +#ifdef CONFIG_NUMA + unsigned apicid, node; + int cpu = smp_processor_id(); + + /* Don't do the funky fallback heuristics the AMD version employs + for now. */ + apicid = phys_proc_id[cpu]; + node = apicid_to_node[apicid]; + if (node == NUMA_NO_NODE) + node = 0; + cpu_to_node[cpu] = node; + + if (acpi_numa > 0) + printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node); +#endif +} + static void __cpuinit init_intel(struct cpuinfo_x86 *c) { /* Cache sizes */ @@ -927,6 +984,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) if (c->x86 >= 15) set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); c->x86_num_cores = intel_num_cpu_cores(c); + + srat_detect_node(); } static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index e3ffcacc8c9..bd33be24a38 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -94,7 +94,7 @@ void __init setup_per_cpu_areas(void) size = PERCPU_ENOUGH_ROOM; #endif - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu_mask (i, cpu_possible_map) { char *ptr; if (!NODE_DATA(cpu_to_node(i))) { @@ -119,7 +119,6 @@ void pda_init(int cpu) asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); wrmsrl(MSR_GS_BASE, cpu_pda + cpu); - pda->me = pda; pda->cpunumber = cpu; pda->irqcount = -1; pda->kernelstack = diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index e5958220d6b..9db9dda161b 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/smp_lock.h> @@ -29,6 +28,8 @@ #include <asm/proto.h> #include <asm/apicdef.h> +#define __cpuinit __init + /* * Smarter SMP flushing macros. * c/o Linus Torvalds. @@ -37,19 +38,41 @@ * writing to user space from interrupts. (Its not allowed anyway). * * Optimizations Manfred Spraul <manfred@colorfullife.com> + * + * More scalable flush, from Andi Kleen + * + * To avoid global state use 8 different call vectors. + * Each CPU uses a specific vector to trigger flushes on other + * CPUs. Depending on the received vector the target CPUs look into + * the right per cpu variable for the flush data. + * + * With more than 8 CPUs they are hashed to the 8 available + * vectors. The limited global vector space forces us to this right now. + * In future when interrupts are split into per CPU domains this could be + * fixed, at the cost of triggering multiple IPIs in some cases. */ -static cpumask_t flush_cpumask; -static struct mm_struct * flush_mm; -static unsigned long flush_va; -static DEFINE_SPINLOCK(tlbstate_lock); +union smp_flush_state { + struct { + cpumask_t flush_cpumask; + struct mm_struct *flush_mm; + unsigned long flush_va; #define FLUSH_ALL -1ULL + spinlock_t tlbstate_lock; + }; + char pad[SMP_CACHE_BYTES]; +} ____cacheline_aligned; + +/* State is put into the per CPU data section, but padded + to a full cache line because other CPUs can access it and we don't + want false sharing in the per cpu data segment. */ +static DEFINE_PER_CPU(union smp_flush_state, flush_state); /* * We cannot call mmdrop() because we are in interrupt context, * instead update mm->cpu_vm_mask. */ -static inline void leave_mm (unsigned long cpu) +static inline void leave_mm(int cpu) { if (read_pda(mmu_state) == TLBSTATE_OK) BUG(); @@ -101,15 +124,25 @@ static inline void leave_mm (unsigned long cpu) * * 1) Flush the tlb entries if the cpu uses the mm that's being flushed. * 2) Leave the mm if we are in the lazy tlb mode. + * + * Interrupts are disabled. */ -asmlinkage void smp_invalidate_interrupt (void) +asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) { - unsigned long cpu; + int cpu; + int sender; + union smp_flush_state *f; - cpu = get_cpu(); + cpu = smp_processor_id(); + /* + * orig_rax contains the interrupt vector - 256. + * Use that to determine where the sender put the data. + */ + sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START; + f = &per_cpu(flush_state, sender); - if (!cpu_isset(cpu, flush_cpumask)) + if (!cpu_isset(cpu, f->flush_cpumask)) goto out; /* * This was a BUG() but until someone can quote me the @@ -120,64 +153,63 @@ asmlinkage void smp_invalidate_interrupt (void) * BUG(); */ - if (flush_mm == read_pda(active_mm)) { + if (f->flush_mm == read_pda(active_mm)) { if (read_pda(mmu_state) == TLBSTATE_OK) { - if (flush_va == FLUSH_ALL) + if (f->flush_va == FLUSH_ALL) local_flush_tlb(); else - __flush_tlb_one(flush_va); + __flush_tlb_one(f->flush_va); } else leave_mm(cpu); } out: ack_APIC_irq(); - cpu_clear(cpu, flush_cpumask); - put_cpu_no_resched(); + cpu_clear(cpu, f->flush_cpumask); } static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, unsigned long va) { - cpumask_t tmp; - /* - * A couple of (to be removed) sanity checks: - * - * - we do not send IPIs to not-yet booted CPUs. - * - current CPU must not be in mask - * - mask must exist :) - */ - BUG_ON(cpus_empty(cpumask)); - cpus_and(tmp, cpumask, cpu_online_map); - BUG_ON(!cpus_equal(tmp, cpumask)); - BUG_ON(cpu_isset(smp_processor_id(), cpumask)); - if (!mm) - BUG(); + int sender; + union smp_flush_state *f; - /* - * I'm not happy about this global shared spinlock in the - * MM hot path, but we'll see how contended it is. - * Temporarily this turns IRQs off, so that lockups are - * detected by the NMI watchdog. - */ - spin_lock(&tlbstate_lock); - - flush_mm = mm; - flush_va = va; - cpus_or(flush_cpumask, cpumask, flush_cpumask); + /* Caller has disabled preemption */ + sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS; + f = &per_cpu(flush_state, sender); + + /* Could avoid this lock when + num_online_cpus() <= NUM_INVALIDATE_TLB_VECTORS, but it is + probably not worth checking this for a cache-hot lock. */ + spin_lock(&f->tlbstate_lock); + + f->flush_mm = mm; + f->flush_va = va; + cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask); /* * We have to send the IPI only to * CPUs affected. */ - send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); + send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender); + + while (!cpus_empty(f->flush_cpumask)) + cpu_relax(); - while (!cpus_empty(flush_cpumask)) - mb(); /* nothing. lockup detection does not belong here */; + f->flush_mm = NULL; + f->flush_va = 0; + spin_unlock(&f->tlbstate_lock); +} - flush_mm = NULL; - flush_va = 0; - spin_unlock(&tlbstate_lock); +int __cpuinit init_smp_flush(void) +{ + int i; + for_each_cpu_mask(i, cpu_possible_map) { + spin_lock_init(&per_cpu(flush_state.tlbstate_lock, i)); + } + return 0; } + +core_initcall(init_smp_flush); void flush_tlb_current_task(void) { @@ -295,8 +327,11 @@ void unlock_ipi_call_lock(void) /* * this function sends a 'generic call function' IPI to one other CPU * in the system. + * + * cpu is a standard Linux logical CPU number. */ -static void __smp_call_function_single (int cpu, void (*func) (void *info), void *info, +static void +__smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, int wait) { struct call_data_struct data; diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 4fb34b5cb1f..e12d7baeb33 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -44,7 +44,6 @@ #include <linux/mm.h> #include <linux/kernel_stat.h> #include <linux/smp_lock.h> -#include <linux/irq.h> #include <linux/bootmem.h> #include <linux/thread_info.h> #include <linux/module.h> @@ -58,6 +57,8 @@ #include <asm/tlbflush.h> #include <asm/proto.h> #include <asm/nmi.h> +#include <asm/irq.h> +#include <asm/hw_irq.h> /* Number of siblings per CPU package */ int smp_num_siblings = 1; @@ -413,8 +414,13 @@ void __cpuinit smp_callin(void) /* * Get our bogomips. + * + * Need to enable IRQs because it can take longer and then + * the NMI watchdog might kill us. */ + local_irq_enable(); calibrate_delay(); + local_irq_disable(); Dprintk("Stack at about %p\n",&cpuid); disable_APIC_timer(); @@ -540,8 +546,8 @@ static void inquire_remote_apic(int apicid) */ apic_wait_icr_idle(); - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]); timeout = 0; do { @@ -574,12 +580,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta /* * Turn INIT on target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* * Send IPI */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); @@ -595,10 +601,10 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta Dprintk("Deasserting INIT.\n"); /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Send IPI */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); timeout = 0; @@ -610,16 +616,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta atomic_set(&init_deasserted, 1); - /* - * Should we send STARTUP IPIs ? - * - * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't send the STARTUP IPIs. - */ - if (APIC_INTEGRATED(apic_version[phys_apicid])) - num_starts = 2; - else - num_starts = 0; + num_starts = 2; /* * Run STARTUP IPI loop. @@ -640,12 +637,11 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta */ /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Boot on the stack */ /* Kick the second */ - apic_write_around(APIC_ICR, APIC_DM_STARTUP - | (start_rip >> 12)); + apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12)); /* * Give the other CPU some time to accept the IPI. @@ -864,17 +860,6 @@ static __cpuinit void smp_cleanup_boot(void) * Reset trampoline flag */ *((volatile int *) phys_to_virt(0x467)) = 0; - -#ifndef CONFIG_HOTPLUG_CPU - /* - * Free pages reserved for SMP bootup. - * When you add hotplug CPU support later remove this - * Note there is more work to be done for later CPU bootup. - */ - - free_page((unsigned long) __va(PAGE_SIZE)); - free_page((unsigned long) __va(SMP_TRAMPOLINE_BASE)); -#endif } /* diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index 0612640d91b..ebb9abf3ce6 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -8,23 +8,8 @@ */ #include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/spinlock.h> -#include <linux/poll.h> -#include <linux/delay.h> -#include <linux/sysrq.h> -#include <linux/proc_fs.h> -#include <linux/irq.h> -#include <linux/pm.h> -#include <linux/device.h> +#include <linux/smp.h> #include <linux/suspend.h> -#include <asm/uaccess.h> -#include <asm/acpi.h> -#include <asm/tlbflush.h> -#include <asm/io.h> #include <asm/proto.h> struct saved_context saved_context; diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 7b6abe05825..2373cb8b862 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/mc146818rtc.h> -#include <linux/irq.h> #include <linux/time.h> #include <linux/ioport.h> #include <linux/module.h> @@ -937,7 +936,6 @@ void __init time_init(void) vxtime.mode = VXTIME_TSC; vxtime.quot = (1000000L << 32) / vxtime_hz; vxtime.tsc_quot = (1000L << 32) / cpu_khz; - vxtime.hz = vxtime_hz; rdtscll_sync(&vxtime.last_tsc); setup_irq(0, &irq0); diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index f238d6078a5..b5e09e6b553 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -47,9 +47,6 @@ #include <asm/proto.h> #include <asm/nmi.h> -#include <linux/irq.h> - - extern struct gate_struct idt_table[256]; asmlinkage void divide_error(void); @@ -324,13 +321,13 @@ void handle_BUG(struct pt_regs *regs) if (__copy_from_user(&f, (struct bug_frame *) regs->rip, sizeof(struct bug_frame))) return; - if ((unsigned long)f.filename < __PAGE_OFFSET || + if (f.filename >= 0 || f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) return; - if (__get_user(tmp, f.filename)) - f.filename = "unmapped filename"; + if (__get_user(tmp, (char *)(long)f.filename)) + f.filename = (int)(long)"unmapped filename"; printk("----------- [cut here ] --------- [please bite here ] ---------\n"); - printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line); + printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", (char *)(long)f.filename, f.line); } #ifdef CONFIG_BUG @@ -343,30 +340,33 @@ void out_of_line_bug(void) static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; -void oops_begin(void) +unsigned long oops_begin(void) { - int cpu = safe_smp_processor_id(); - /* racy, but better than risking deadlock. */ - local_irq_disable(); + int cpu = safe_smp_processor_id(); + unsigned long flags; + + /* racy, but better than risking deadlock. */ + local_irq_save(flags); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; else - spin_lock(&die_lock); + spin_lock(&die_lock); } - die_owner = cpu; + die_owner = cpu; console_verbose(); - bust_spinlocks(1); + bust_spinlocks(1); + return flags; } -void oops_end(void) +void oops_end(unsigned long flags) { die_owner = -1; - bust_spinlocks(0); - spin_unlock(&die_lock); + bust_spinlocks(0); + spin_unlock_irqrestore(&die_lock, flags); if (panic_on_oops) - panic("Oops"); -} + panic("Oops"); +} void __die(const char * str, struct pt_regs * regs, long err) { @@ -392,10 +392,11 @@ void __die(const char * str, struct pt_regs * regs, long err) void die(const char * str, struct pt_regs * regs, long err) { - oops_begin(); + unsigned long flags = oops_begin(); + handle_BUG(regs); __die(str, regs, err); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) @@ -406,7 +407,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e void die_nmi(char *str, struct pt_regs *regs) { - oops_begin(); + unsigned long flags = oops_begin(); + /* * We are in trouble anyway, lets at least try * to get a message out. @@ -416,7 +418,7 @@ void die_nmi(char *str, struct pt_regs *regs) if (panic_on_timeout || panic_on_oops) panic("nmi watchdog"); printk("console shuts up ...\n"); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } @@ -790,13 +792,16 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs) */ cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); - switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { + switch (swd & ~cwd & 0x3f) { case 0x000: default: break; case 0x001: /* Invalid Op */ - case 0x041: /* Stack Fault */ - case 0x241: /* Stack Fault | Direction */ + /* + * swd & 0x240 == 0x040: Stack Underflow + * swd & 0x240 == 0x240: Stack Overflow + * User must clear the SF bit (0x40) if set + */ info.si_code = FPE_FLTINV; break; case 0x002: /* Denormalize */ diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 2e573442594..70a0bd16085 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -107,7 +107,7 @@ static force_inline long time_syscall(long *t) return secs; } -static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) +int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) { if (unlikely(!__sysctl_vsyscall)) return gettimeofday(tv,tz); @@ -120,7 +120,7 @@ static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz /* This will break when the xtime seconds get inaccurate, but that is * unlikely */ -static time_t __vsyscall(1) vtime(time_t *t) +time_t __vsyscall(1) vtime(time_t *t) { if (unlikely(!__sysctl_vsyscall)) return time_syscall(t); @@ -129,12 +129,12 @@ static time_t __vsyscall(1) vtime(time_t *t) return __xtime.tv_sec; } -static long __vsyscall(2) venosys_0(void) +long __vsyscall(2) venosys_0(void) { return -ENOSYS; } -static long __vsyscall(3) venosys_1(void) +long __vsyscall(3) venosys_1(void) { return -ENOSYS; } diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 816732d8858..b75b872ec15 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig) static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, unsigned long error_code) { - oops_begin(); + unsigned long flags = oops_begin(); + printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", current->comm, address); dump_pagetable(address); __die("Bad pagetable", regs, error_code); - oops_end(); + oops_end(flags); do_exit(SIGKILL); } @@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long address; const struct exception_table_entry *fixup; int write; + unsigned long flags; siginfo_t info; #ifdef CONFIG_CHECKING @@ -521,7 +523,7 @@ no_context: * terminate things with extreme prejudice. */ - oops_begin(); + flags = oops_begin(); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -534,7 +536,7 @@ no_context: __die("Oops", regs, error_code); /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); - oops_end(); + oops_end(flags); do_exit(SIGKILL); /* diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index aa4a5189ece..e60a1a848de 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -57,31 +57,31 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; + long i, total = 0, reserved = 0; + long shared = 0, cached = 0; pg_data_t *pgdat; struct page *page; - printk("Mem-info:\n"); + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pfn_to_page(pgdat->node_start_pfn + i); total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; } } - printk("%d pages of RAM\n", total); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + printk(KERN_INFO "%lu pages of RAM\n", total); + printk(KERN_INFO "%lu reserved pages\n",reserved); + printk(KERN_INFO "%lu pages shared\n",shared); + printk(KERN_INFO "%lu pages swap cached\n",cached); } /* References to section boundaries */ @@ -381,41 +381,14 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size) __flush_tlb_all(); } -static inline int page_is_ram (unsigned long pagenr) -{ - int i; - - for (i = 0; i < e820.nr_map; i++) { - unsigned long addr, end; - - if (e820.map[i].type != E820_RAM) /* not usable memory */ - continue; - /* - * !!!FIXME!!! Some BIOSen report areas as RAM that - * are not. Notably the 640->1Mb area. We need a sanity - * check here. - */ - addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < end)) - return 1; - } - return 0; -} - -extern int swiotlb_force; - static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall; void __init mem_init(void) { - int codesize, reservedpages, datasize, initsize; - int tmp; + long codesize, reservedpages, datasize, initsize; #ifdef CONFIG_SWIOTLB - if (swiotlb_force) - swiotlb = 1; if (!iommu_aperture && (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu)) swiotlb = 1; @@ -436,25 +409,11 @@ void __init mem_init(void) /* this will put all low memory onto the freelists */ #ifdef CONFIG_NUMA - totalram_pages += numa_free_all_bootmem(); - tmp = 0; - /* should count reserved pages here for all nodes */ + totalram_pages = numa_free_all_bootmem(); #else - -#ifdef CONFIG_FLATMEM - max_mapnr = end_pfn; - if (!mem_map) BUG(); -#endif - - totalram_pages += free_all_bootmem(); - - for (tmp = 0; tmp < end_pfn; tmp++) - /* - * Only count reserved RAM pages - */ - if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) - reservedpages++; + totalram_pages = free_all_bootmem(); #endif + reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn); after_bootmem = 1; @@ -471,7 +430,7 @@ void __init mem_init(void) kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, VSYSCALL_END - VSYSCALL_START); - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), end_pfn << (PAGE_SHIFT-10), codesize >> 10, diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c index ec35747aacd..65417b040c1 100644 --- a/arch/x86_64/mm/k8topology.c +++ b/arch/x86_64/mm/k8topology.c @@ -45,10 +45,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) unsigned long prevbase; struct node nodes[8]; int nodeid, i, nb; + unsigned char nodeids[8]; int found = 0; u32 reg; unsigned numnodes; nodemask_t nodes_parsed; + unsigned dualcore = 0; nodes_clear(nodes_parsed); @@ -67,11 +69,15 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) prevbase = 0; for (i = 0; i < 8; i++) { unsigned long base,limit; - + u32 nodeid; + + /* Undefined before E stepping, but hopefully 0 */ + dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1; base = read_pci_config(0, nb, 1, 0x40 + i*8); limit = read_pci_config(0, nb, 1, 0x44 + i*8); nodeid = limit & 7; + nodeids[i] = nodeid; if ((base & 3) == 0) { if (i < numnodes) printk("Skipping disabled node %d\n", i); @@ -157,8 +163,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) for (i = 0; i < 8; i++) { if (nodes[i].start != nodes[i].end) { - /* assume 1:1 NODE:CPU */ - cpu_to_node[i] = i; + nodeid = nodeids[i]; + apicid_to_node[nodeid << dualcore] = i; + apicid_to_node[(nodeid << dualcore) + dualcore] = i; setup_node_bootmem(i, nodes[i].start, nodes[i].end); } } diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 04f7a33e144..80a49d9bd8a 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -28,8 +28,13 @@ bootmem_data_t plat_node_bdata[MAX_NUMNODES]; int memnode_shift; u8 memnodemap[NODEMAPSIZE]; -unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE }; -cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; +unsigned char cpu_to_node[NR_CPUS] __read_mostly = { + [0 ... NR_CPUS-1] = NUMA_NO_NODE +}; +unsigned char apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = { + [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE +}; +cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; int numa_off __initdata; diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 8e3d097a9dd..4b2e844c15a 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -20,14 +20,20 @@ static struct acpi_table_slit *acpi_slit; -/* Internal processor count */ -static unsigned int __initdata num_processors = 0; - static nodemask_t nodes_parsed __initdata; static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; static __u8 pxm2node[256] = { [0 ... 255] = 0xff }; +static int node_to_pxm(int n); + +int pxm_to_node(int pxm) +{ + if ((unsigned)pxm >= 256) + return 0; + return pxm2node[pxm]; +} + static __init int setup_node(int pxm) { unsigned node = pxm2node[pxm]; @@ -44,14 +50,14 @@ static __init int setup_node(int pxm) static __init int conflicting_nodes(unsigned long start, unsigned long end) { int i; - for_each_online_node(i) { + for_each_node_mask(i, nodes_parsed) { struct node *nd = &nodes[i]; if (nd->start == nd->end) continue; if (nd->end > start && nd->start < end) - return 1; + return i; if (nd->end == end && nd->start == start) - return 1; + return i; } return -1; } @@ -75,8 +81,11 @@ static __init void cutoff_node(int i, unsigned long start, unsigned long end) static __init void bad_srat(void) { + int i; printk(KERN_ERR "SRAT: SRAT not used.\n"); acpi_numa = -1; + for (i = 0; i < MAX_LOCAL_APIC; i++) + apicid_to_node[i] = NUMA_NO_NODE; } static __init inline int srat_disabled(void) @@ -104,18 +113,10 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) bad_srat(); return; } - if (num_processors >= NR_CPUS) { - printk(KERN_ERR "SRAT: Processor #%d (lapic %u) INVALID. (Max ID: %d).\n", - num_processors, pa->apic_id, NR_CPUS); - bad_srat(); - return; - } - cpu_to_node[num_processors] = node; + apicid_to_node[pa->apic_id] = node; acpi_numa = 1; - printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> CPU %u -> Node %u\n", - pxm, pa->apic_id, num_processors, node); - - num_processors++; + printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n", + pxm, pa->apic_id, node); } /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ @@ -143,10 +144,15 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n", start, end); i = conflicting_nodes(start, end); - if (i >= 0) { + if (i == node) { + printk(KERN_WARNING + "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n", + pxm, start, end, nodes[i].start, nodes[i].end); + } else if (i >= 0) { printk(KERN_ERR - "SRAT: pxm %d overlap %lx-%lx with node %d(%Lx-%Lx)\n", - pxm, start, end, i, nodes[i].start, nodes[i].end); + "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n", + pxm, start, end, node_to_pxm(i), + nodes[i].start, nodes[i].end); bad_srat(); return; } @@ -174,6 +180,14 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) int i; if (acpi_numa <= 0) return -1; + + /* First clean up the node list */ + for_each_node_mask(i, nodes_parsed) { + cutoff_node(i, start, end); + if (nodes[i].start == nodes[i].end) + node_clear(i, nodes_parsed); + } + memnode_shift = compute_hash_shift(nodes, nodes_weight(nodes_parsed)); if (memnode_shift < 0) { printk(KERN_ERR @@ -181,16 +195,10 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) bad_srat(); return -1; } - for (i = 0; i < MAX_NUMNODES; i++) { - if (!node_isset(i, nodes_parsed)) - continue; - cutoff_node(i, start, end); - if (nodes[i].start == nodes[i].end) { - node_clear(i, nodes_parsed); - continue; - } + + /* Finally register nodes */ + for_each_node_mask(i, nodes_parsed) setup_node_bootmem(i, nodes[i].start, nodes[i].end); - } for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; @@ -201,7 +209,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return 0; } -int node_to_pxm(int n) +static int node_to_pxm(int n) { int i; if (pxm2node[n] == n) diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c index d80c323669e..3acf60ded2a 100644 --- a/arch/x86_64/pci/k8-bus.c +++ b/arch/x86_64/pci/k8-bus.c @@ -58,10 +58,16 @@ fill_mp_bus_to_cpumask(void) for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus); j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus); j++) { - int node = NODE_ID(nid); + struct pci_bus *bus; + long node = NODE_ID(nid); + /* Algorithm a bit dumb, but + it shouldn't matter here */ + bus = pci_find_bus(0, j); + if (!bus) + continue; if (!node_online(node)) node = 0; - pci_bus_to_node[j] = node; + bus->sysdata = (void *)node; } } } diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index 657e88aa090..a0838c4a94e 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -111,13 +111,6 @@ static int __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) return 0; - /* Kludge for now. Don't use mmconfig on AMD systems because - those have some busses where mmconfig doesn't work, - and we don't parse ACPI MCFG well enough to handle that. - Remove when proper handling is added. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - return 0; - /* RED-PEN i386 doesn't do _nocache right now */ pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); if (pci_mmcfg_virt == NULL) { diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 721ba808604..0e9e586e9ba 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "10" +#define VERSION "12" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" @@ -7,12 +7,12 @@ * default is 16, which is 15 partitions plus the whole disk */ #ifndef AOE_PARTITIONS -#define AOE_PARTITIONS 16 +#define AOE_PARTITIONS (16) #endif -#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor)) -#define AOEMAJOR(sysminor) ((sysminor) / 10) -#define AOEMINOR(sysminor) ((sysminor) % 10) +#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor)) +#define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF) +#define AOEMINOR(sysminor) ((sysminor) % NPERSHELF) #define WHITESPACE " \t\v\f\n" enum { @@ -83,7 +83,7 @@ enum { enum { MAXATADATA = 1024, - NPERSHELF = 10, + NPERSHELF = 16, /* number of slots per shelf address */ FREETAG = -1, MIN_BUFS = 8, }; diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index c3898afce3a..fa789ea36bb 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -139,6 +139,15 @@ config SA1100_WATCHDOG To compile this driver as a module, choose M here: the module will be called sa1100_wdt. +config MPCORE_WATCHDOG + tristate "MPcore watchdog" + depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS + help + Watchdog timer embedded into the MPcore system. + + To compile this driver as a module, choose M here: the + module will be called mpcore_wdt. + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index cfeac6f1013..bc6f5fe88c8 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o +obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c new file mode 100644 index 00000000000..c694eee1fb2 --- /dev/null +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -0,0 +1,434 @@ +/* + * Watchdog driver for the mpcore watchdog timer + * + * (c) Copyright 2004 ARM Limited + * + * Based on the SoftDog driver: + * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. + * http://www.redhat.com + * + * 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. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> + * + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <asm/uaccess.h> + +struct mpcore_wdt { + unsigned long timer_alive; + struct device *dev; + void __iomem *base; + int irq; + unsigned int perturb; + char expect_close; +}; + +static struct platform_device *mpcore_wdt_dev; + +extern unsigned int mpcore_timer_rate; + +#define TIMER_MARGIN 60 +static int mpcore_margin = TIMER_MARGIN; +module_param(mpcore_margin, int, 0); +MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +#define ONLY_TESTING 0 +static int mpcore_noboot = ONLY_TESTING; +module_param(mpcore_noboot, int, 0); +MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore reboots, 0 to reboot (default=" __MODULE_STRING(ONLY_TESTING) ")"); + +/* + * This is the interrupt handler. Note that we only use this + * in testing mode, so don't actually do a reboot here. + */ +static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs) +{ + struct mpcore_wdt *wdt = arg; + + /* Check it really was our interrupt */ + if (readl(wdt->base + TWD_WDOG_INTSTAT)) { + dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n"); + + /* Clear the interrupt on the watchdog */ + writel(1, wdt->base + TWD_WDOG_INTSTAT); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +/* + * mpcore_wdt_keepalive - reload the timer + * + * Note that the spec says a DIFFERENT value must be written to the reload + * register each time. The "perturb" variable deals with this by adding 1 + * to the count every other time the function is called. + */ +static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt) +{ + unsigned int count; + + /* Assume prescale is set to 256 */ + count = (mpcore_timer_rate / 256) * mpcore_margin; + + /* Reload the counter */ + writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); + + wdt->perturb = wdt->perturb ? 0 : 1; +} + +static void mpcore_wdt_stop(struct mpcore_wdt *wdt) +{ + writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); + writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); + writel(0x0, wdt->base + TWD_WDOG_CONTROL); +} + +static void mpcore_wdt_start(struct mpcore_wdt *wdt) +{ + dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); + + /* This loads the count register but does NOT start the count yet */ + mpcore_wdt_keepalive(wdt); + + if (mpcore_noboot) { + /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */ + writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL); + } else { + /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ + writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); + } +} + +static int mpcore_wdt_set_heartbeat(int t) +{ + if (t < 0x0001 || t > 0xFFFF) + return -EINVAL; + + mpcore_margin = t; + return 0; +} + +/* + * /dev/watchdog handling + */ +static int mpcore_wdt_open(struct inode *inode, struct file *file) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(&mpcore_wdt_dev->dev); + + if (test_and_set_bit(0, &wdt->timer_alive)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + file->private_data = wdt; + + /* + * Activate timer + */ + mpcore_wdt_start(wdt); + + return nonseekable_open(inode, file); +} + +static int mpcore_wdt_release(struct inode *inode, struct file *file) +{ + struct mpcore_wdt *wdt = file->private_data; + + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (wdt->expect_close == 42) { + mpcore_wdt_stop(wdt); + } else { + dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n"); + mpcore_wdt_keepalive(wdt); + } + clear_bit(0, &wdt->timer_alive); + wdt->expect_close = 0; + return 0; +} + +static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + struct mpcore_wdt *wdt = file->private_data; + + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + wdt->expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + wdt->expect_close = 42; + } + } + mpcore_wdt_keepalive(wdt); + } + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .identity = "MPcore Watchdog", +}; + +static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mpcore_wdt *wdt = file->private_data; + int ret; + union { + struct watchdog_info ident; + int i; + } uarg; + + if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg)) + return -ENOIOCTLCMD; + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd)); + if (ret) + return -EFAULT; + } + + switch (cmd) { + case WDIOC_GETSUPPORT: + uarg.ident = ident; + ret = 0; + break; + + case WDIOC_SETOPTIONS: + ret = -EINVAL; + if (uarg.i & WDIOS_DISABLECARD) { + mpcore_wdt_stop(wdt); + ret = 0; + } + if (uarg.i & WDIOS_ENABLECARD) { + mpcore_wdt_start(wdt); + ret = 0; + } + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + uarg.i = 0; + ret = 0; + break; + + case WDIOC_KEEPALIVE: + mpcore_wdt_keepalive(wdt); + ret = 0; + break; + + case WDIOC_SETTIMEOUT: + ret = mpcore_wdt_set_heartbeat(uarg.i); + if (ret) + break; + + mpcore_wdt_keepalive(wdt); + /* Fall */ + case WDIOC_GETTIMEOUT: + uarg.i = mpcore_margin; + ret = 0; + break; + + default: + return -ENOIOCTLCMD; + } + + if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { + ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd)); + if (ret) + ret = -EFAULT; + } + return ret; +} + +/* + * System shutdown handler. Turn off the watchdog if we're + * restarting or halting the system. + */ +static void mpcore_wdt_shutdown(struct device *_dev) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(_dev); + + if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT) + mpcore_wdt_stop(wdt); +} + +/* + * Kernel Interfaces + */ +static struct file_operations mpcore_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = mpcore_wdt_write, + .ioctl = mpcore_wdt_ioctl, + .open = mpcore_wdt_open, + .release = mpcore_wdt_release, +}; + +static struct miscdevice mpcore_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mpcore_wdt_fops, +}; + +static int __devinit mpcore_wdt_probe(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct mpcore_wdt *wdt; + struct resource *res; + int ret; + + /* We only accept one device, and it must have an id of -1 */ + if (dev->id != -1) + return -ENODEV; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto err_out; + } + + wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL); + if (!wdt) { + ret = -ENOMEM; + goto err_out; + } + memset(wdt, 0, sizeof(struct mpcore_wdt)); + + wdt->dev = &dev->dev; + wdt->irq = platform_get_irq(dev, 0); + wdt->base = ioremap(res->start, res->end - res->start + 1); + if (!wdt->base) { + ret = -ENOMEM; + goto err_free; + } + + mpcore_wdt_miscdev.dev = &dev->dev; + ret = misc_register(&mpcore_wdt_miscdev); + if (ret) { + dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto err_misc; + } + + ret = request_irq(wdt->irq, mpcore_wdt_fire, SA_INTERRUPT, "mpcore_wdt", wdt); + if (ret) { + dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq); + goto err_irq; + } + + mpcore_wdt_stop(wdt); + dev_set_drvdata(&dev->dev, wdt); + mpcore_wdt_dev = dev; + + return 0; + + err_irq: + misc_deregister(&mpcore_wdt_miscdev); + err_misc: + iounmap(wdt->base); + err_free: + kfree(wdt); + err_out: + return ret; +} + +static int __devexit mpcore_wdt_remove(struct device *dev) +{ + struct mpcore_wdt *wdt = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + misc_deregister(&mpcore_wdt_miscdev); + + mpcore_wdt_dev = NULL; + + free_irq(wdt->irq, wdt); + iounmap(wdt->base); + kfree(wdt); + return 0; +} + +static struct device_driver mpcore_wdt_driver = { + .name = "mpcore_wdt", + .bus = &platform_bus_type, + .probe = mpcore_wdt_probe, + .remove = __devexit_p(mpcore_wdt_remove), + .shutdown = mpcore_wdt_shutdown, +}; + +static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n"; + +static int __init mpcore_wdt_init(void) +{ + /* + * Check that the margin value is within it's range; + * if not reset to the default + */ + if (mpcore_wdt_set_heartbeat(mpcore_margin)) { + mpcore_wdt_set_heartbeat(TIMER_MARGIN); + printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n", + TIMER_MARGIN); + } + + printk(banner, mpcore_noboot, mpcore_margin, nowayout); + + return driver_register(&mpcore_wdt_driver); +} + +static void __exit mpcore_wdt_exit(void) +{ + driver_unregister(&mpcore_wdt_driver); +} + +module_init(mpcore_wdt_init); +module_exit(mpcore_wdt_exit); + +MODULE_AUTHOR("ARM Limited"); +MODULE_DESCRIPTION("MPcore Watchdog Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 138dc50270e..7e72e922b41 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -411,6 +411,23 @@ config SENSORS_W83627EHF This driver can also be built as a module. If so, the module will be called w83627ehf. +config SENSORS_HDAPS + tristate "IBM Hard Drive Active Protection System (hdaps)" + depends on HWMON && INPUT && X86 + default n + help + This driver provides support for the IBM Hard Drive Active Protection + System (hdaps), which provides an accelerometer and other misc. data. + Supported laptops include the IBM ThinkPad T41, T42, T43, and R51. + The accelerometer data is readable via sysfs. + + This driver also provides an input class device, allowing the + laptop to act as a pinball machine-esque mouse. This is off by + default but enabled via sysfs or the module parameter "mousedev". + + Say Y here if you have an applicable laptop and want to experience + the awesome power of hdaps. + config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" depends on HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 381f1bf04cc..f7d6a2f61ee 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_FSCHER) += fscher.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o +obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c new file mode 100644 index 00000000000..eaebfc14c93 --- /dev/null +++ b/drivers/hwmon/hdaps.c @@ -0,0 +1,739 @@ +/* + * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System + * + * Copyright (C) 2005 Robert Love <rml@novell.com> + * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com> + * + * The HardDisk Active Protection System (hdaps) is present in the IBM ThinkPad + * T41, T42, T43, R51, and X40, at least. It provides a basic two-axis + * accelerometer and other data, such as the device's temperature. + * + * Based on the document by Mark A. Smith available at + * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial + * and error. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/dmi.h> +#include <asm/io.h> + +#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ +#define HDAPS_NR_PORTS 0x30 /* 0x1600 - 0x162f */ + +#define STATE_FRESH 0x50 /* accelerometer data is fresh */ + +#define REFRESH_ASYNC 0x00 /* do asynchronous refresh */ +#define REFRESH_SYNC 0x01 /* do synchronous refresh */ + +#define HDAPS_PORT_STATE 0x1611 /* device state */ +#define HDAPS_PORT_YPOS 0x1612 /* y-axis position */ +#define HDAPS_PORT_XPOS 0x1614 /* x-axis position */ +#define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in celcius */ +#define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */ +#define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */ +#define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */ +#define HDAPS_PORT_UNKNOWN 0x161c /* what is this? */ +#define HDAPS_PORT_KMACT 0x161d /* keyboard or mouse activity */ + +#define HDAPS_READ_MASK 0xff /* some reads have the low 8 bits set */ + +#define KEYBD_MASK 0x20 /* set if keyboard activity */ +#define MOUSE_MASK 0x40 /* set if mouse activity */ +#define KEYBD_ISSET(n) (!! (n & KEYBD_MASK)) /* keyboard used? */ +#define MOUSE_ISSET(n) (!! (n & MOUSE_MASK)) /* mouse used? */ + +#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ +#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ + +static struct platform_device *pdev; +static struct input_dev hdaps_idev; +static struct timer_list hdaps_timer; +static unsigned int hdaps_mousedev_threshold = 4; +static unsigned long hdaps_poll_ms = 50; +static unsigned int hdaps_mousedev; +static unsigned int hdaps_invert; +static u8 km_activity; +static int rest_x; +static int rest_y; + +static DECLARE_MUTEX(hdaps_sem); + +/* + * __get_latch - Get the value from a given port. Callers must hold hdaps_sem. + */ +static inline u8 __get_latch(u16 port) +{ + return inb(port) & HDAPS_READ_MASK; +} + +/* + * __check_latch - Check a port latch for a given value. Callers must hold + * hdaps_sem. Returns zero if the port contains the given value. + */ +static inline unsigned int __check_latch(u16 port, u8 val) +{ + if (__get_latch(port) == val) + return 0; + return -EINVAL; +} + +/* + * __wait_latch - Wait up to 100us for a port latch to get a certain value, + * returning zero if the value is obtained. Callers must hold hdaps_sem. + */ +static unsigned int __wait_latch(u16 port, u8 val) +{ + unsigned int i; + + for (i = 0; i < 20; i++) { + if (!__check_latch(port, val)) + return 0; + udelay(5); + } + + return -EINVAL; +} + +/* + * __device_refresh - Request a refresh from the accelerometer. + * + * If sync is REFRESH_SYNC, we perform a synchronous refresh and will wait. + * Returns zero if successful and nonzero on error. + * + * If sync is REFRESH_ASYNC, we merely kick off a new refresh if the device is + * not up-to-date. Always returns zero. + * + * Callers must hold hdaps_sem. + */ +static int __device_refresh(unsigned int sync) +{ + u8 state; + + udelay(100); + + state = inb(0x1604); + if (state == STATE_FRESH) + return 0; + + outb(0x11, 0x1610); + outb(0x01, 0x161f); + if (sync == REFRESH_ASYNC) + return 0; + + return __wait_latch(0x1604, STATE_FRESH); +} + +/* + * __device_complete - Indicate to the accelerometer that we are done reading + * data, and then initiate an async refresh. Callers must hold hdaps_sem. + */ +static inline void __device_complete(void) +{ + inb(0x161f); + inb(0x1604); + __device_refresh(REFRESH_ASYNC); +} + +static int __hdaps_readb_one(unsigned int port, u8 *val) +{ + /* do a sync refresh -- we need to be sure that we read fresh data */ + if (__device_refresh(REFRESH_SYNC)) + return -EIO; + + *val = inb(port); + __device_complete(); + + return 0; +} + +/* + * hdaps_readb_one - reads a byte from a single I/O port, placing the value in + * the given pointer. Returns zero on success or a negative error on failure. + * Can sleep. + */ +static int hdaps_readb_one(unsigned int port, u8 *val) +{ + int ret; + + down(&hdaps_sem); + ret = __hdaps_readb_one(port, val); + up(&hdaps_sem); + + return ret; +} + +static int __hdaps_read_pair(unsigned int port1, unsigned int port2, + int *x, int *y) +{ + /* do a sync refresh -- we need to be sure that we read fresh data */ + if (__device_refresh(REFRESH_SYNC)) + return -EIO; + + *y = inw(port2); + *x = inw(port1); + km_activity = inb(HDAPS_PORT_KMACT); + __device_complete(); + + /* if hdaps_invert is set, negate the two values */ + if (hdaps_invert) { + *x = -*x; + *y = -*y; + } + + return 0; +} + +/* + * hdaps_read_pair - reads the values from a pair of ports, placing the values + * in the given pointers. Returns zero on success. Can sleep. + */ +static int hdaps_read_pair(unsigned int port1, unsigned int port2, + int *val1, int *val2) +{ + int ret; + + down(&hdaps_sem); + ret = __hdaps_read_pair(port1, port2, val1, val2); + up(&hdaps_sem); + + return ret; +} + +/* initialize the accelerometer */ +static int hdaps_device_init(void) +{ + unsigned int total_msecs = INIT_TIMEOUT_MSECS; + int ret = -ENXIO; + + down(&hdaps_sem); + + outb(0x13, 0x1610); + outb(0x01, 0x161f); + if (__wait_latch(0x161f, 0x00)) + goto out; + + /* + * The 0x03 value appears to only work on some thinkpads, such as the + * T42p. Others return 0x01. + * + * The 0x02 value occurs when the chip has been previously initialized. + */ + if (__check_latch(0x1611, 0x03) && + __check_latch(0x1611, 0x02) && + __check_latch(0x1611, 0x01)) + goto out; + + printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n", + __get_latch(0x1611)); + + outb(0x17, 0x1610); + outb(0x81, 0x1611); + outb(0x01, 0x161f); + if (__wait_latch(0x161f, 0x00)) + goto out; + if (__wait_latch(0x1611, 0x00)) + goto out; + if (__wait_latch(0x1612, 0x60)) + goto out; + if (__wait_latch(0x1613, 0x00)) + goto out; + outb(0x14, 0x1610); + outb(0x01, 0x1611); + outb(0x01, 0x161f); + if (__wait_latch(0x161f, 0x00)) + goto out; + outb(0x10, 0x1610); + outb(0xc8, 0x1611); + outb(0x00, 0x1612); + outb(0x02, 0x1613); + outb(0x01, 0x161f); + if (__wait_latch(0x161f, 0x00)) + goto out; + if (__device_refresh(REFRESH_SYNC)) + goto out; + if (__wait_latch(0x1611, 0x00)) + goto out; + + /* we have done our dance, now let's wait for the applause */ + while (total_msecs > 0) { + u8 ignored; + + /* a read of the device helps push it into action */ + __hdaps_readb_one(HDAPS_PORT_UNKNOWN, &ignored); + if (!__wait_latch(0x1611, 0x02)) { + ret = 0; + break; + } + + msleep(INIT_WAIT_MSECS); + total_msecs -= INIT_WAIT_MSECS; + } + +out: + up(&hdaps_sem); + return ret; +} + + +/* Input class stuff */ + +/* + * hdaps_calibrate - Zero out our "resting" values. Callers must hold hdaps_sem. + */ +static void hdaps_calibrate(void) +{ + int x, y; + + if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) + return; + + rest_x = x; + rest_y = y; +} + +static void hdaps_mousedev_poll(unsigned long unused) +{ + int x, y; + + /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ + if (down_trylock(&hdaps_sem)) { + mod_timer(&hdaps_timer,jiffies+msecs_to_jiffies(hdaps_poll_ms)); + return; + } + + if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) + goto out; + + x -= rest_x; + y -= rest_y; + if (abs(x) > hdaps_mousedev_threshold) + input_report_rel(&hdaps_idev, REL_X, x); + if (abs(y) > hdaps_mousedev_threshold) + input_report_rel(&hdaps_idev, REL_Y, y); + input_sync(&hdaps_idev); + + mod_timer(&hdaps_timer, jiffies + msecs_to_jiffies(hdaps_poll_ms)); + +out: + up(&hdaps_sem); +} + +/* + * hdaps_mousedev_enable - enable the input class device. Can sleep. + */ +static void hdaps_mousedev_enable(void) +{ + down(&hdaps_sem); + + /* calibrate the device before enabling */ + hdaps_calibrate(); + + /* initialize the input class */ + init_input_dev(&hdaps_idev); + hdaps_idev.dev = &pdev->dev; + hdaps_idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + hdaps_idev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + hdaps_idev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT); + input_register_device(&hdaps_idev); + + /* start up our timer */ + init_timer(&hdaps_timer); + hdaps_timer.function = hdaps_mousedev_poll; + hdaps_timer.expires = jiffies + msecs_to_jiffies(hdaps_poll_ms); + add_timer(&hdaps_timer); + + hdaps_mousedev = 1; + + up(&hdaps_sem); + + printk(KERN_INFO "hdaps: input device enabled.\n"); +} + +/* + * hdaps_mousedev_disable - disable the input class device. Caller must hold + * hdaps_sem. + */ +static void hdaps_mousedev_disable(void) +{ + down(&hdaps_sem); + if (hdaps_mousedev) { + hdaps_mousedev = 0; + del_timer_sync(&hdaps_timer); + input_unregister_device(&hdaps_idev); + } + up(&hdaps_sem); +} + + +/* Device model stuff */ + +static int hdaps_probe(struct device *dev) +{ + int ret; + + ret = hdaps_device_init(); + if (ret) + return ret; + + printk(KERN_INFO "hdaps: device successfully initialized.\n"); + return 0; +} + +static int hdaps_resume(struct device *dev, u32 level) +{ + if (level == RESUME_ENABLE) + return hdaps_device_init(); + return 0; +} + +static struct device_driver hdaps_driver = { + .name = "hdaps", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .probe = hdaps_probe, + .resume = hdaps_resume +}; + + +/* Sysfs Files */ + +static ssize_t hdaps_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, x, y; + + ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y); + if (ret) + return ret; + + return sprintf(buf, "(%d,%d)\n", x, y); +} + +static ssize_t hdaps_variance_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, x, y; + + ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y); + if (ret) + return ret; + + return sprintf(buf, "(%d,%d)\n", x, y); +} + +static ssize_t hdaps_temp1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 temp; + int ret; + + ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", temp); +} + +static ssize_t hdaps_temp2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 temp; + int ret; + + ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", temp); +} + +static ssize_t hdaps_keyboard_activity_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity)); +} + +static ssize_t hdaps_mouse_activity_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity)); +} + +static ssize_t hdaps_calibrate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "(%d,%d)\n", rest_x, rest_y); +} + +static ssize_t hdaps_calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + down(&hdaps_sem); + hdaps_calibrate(); + up(&hdaps_sem); + + return count; +} + +static ssize_t hdaps_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", hdaps_invert); +} + +static ssize_t hdaps_invert_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int invert; + + if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0)) + return -EINVAL; + + hdaps_invert = invert; + hdaps_calibrate(); + + return count; +} + +static ssize_t hdaps_mousedev_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hdaps_mousedev); +} + +static ssize_t hdaps_mousedev_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int enable; + + if (sscanf(buf, "%d", &enable) != 1) + return -EINVAL; + + if (enable == 1) + hdaps_mousedev_enable(); + else if (enable == 0) + hdaps_mousedev_disable(); + else + return -EINVAL; + + return count; +} + +static ssize_t hdaps_poll_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", hdaps_poll_ms); +} + +static ssize_t hdaps_poll_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int poll; + + if (sscanf(buf, "%u", &poll) != 1 || poll == 0) + return -EINVAL; + hdaps_poll_ms = poll; + + return count; +} + +static ssize_t hdaps_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", hdaps_mousedev_threshold); +} + +static ssize_t hdaps_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int threshold; + + if (sscanf(buf, "%u", &threshold) != 1 || threshold == 0) + return -EINVAL; + hdaps_mousedev_threshold = threshold; + + return count; +} + +static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL); +static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL); +static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL); +static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL); +static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL); +static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL); +static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store); +static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store); +static DEVICE_ATTR(mousedev, 0644, hdaps_mousedev_show, hdaps_mousedev_store); +static DEVICE_ATTR(mousedev_poll_ms, 0644, hdaps_poll_show, hdaps_poll_store); +static DEVICE_ATTR(mousedev_threshold, 0644, hdaps_threshold_show, + hdaps_threshold_store); + +static struct attribute *hdaps_attributes[] = { + &dev_attr_position.attr, + &dev_attr_variance.attr, + &dev_attr_temp1.attr, + &dev_attr_temp2.attr, + &dev_attr_keyboard_activity.attr, + &dev_attr_mouse_activity.attr, + &dev_attr_calibrate.attr, + &dev_attr_mousedev.attr, + &dev_attr_mousedev_threshold.attr, + &dev_attr_mousedev_poll_ms.attr, + &dev_attr_invert.attr, + NULL, +}; + +static struct attribute_group hdaps_attribute_group = { + .attrs = hdaps_attributes, +}; + + +/* Module stuff */ + +/* + * XXX: We should be able to return nonzero and halt the detection process. + * But there is a bug in dmi_check_system() where a nonzero return from the + * first match will result in a return of failure from dmi_check_system(). + * I fixed this; the patch is in 2.6-mm. Once in Linus's tree we can make + * hdaps_dmi_match_invert() return hdaps_dmi_match(), which in turn returns 1. + */ +static int hdaps_dmi_match(struct dmi_system_id *id) +{ + printk(KERN_INFO "hdaps: %s detected.\n", id->ident); + return 0; +} + +static int hdaps_dmi_match_invert(struct dmi_system_id *id) +{ + hdaps_invert = 1; + printk(KERN_INFO "hdaps: inverting axis readings.\n"); + return 0; +} + +#define HDAPS_DMI_MATCH_NORMAL(model) { \ + .ident = "IBM " model, \ + .callback = hdaps_dmi_match, \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \ + DMI_MATCH(DMI_PRODUCT_VERSION, model) \ + } \ +} + +#define HDAPS_DMI_MATCH_INVERT(model) { \ + .ident = "IBM " model, \ + .callback = hdaps_dmi_match_invert, \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \ + DMI_MATCH(DMI_PRODUCT_VERSION, model) \ + } \ +} + +static int __init hdaps_init(void) +{ + int ret; + + /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */ + struct dmi_system_id hdaps_whitelist[] = { + HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"), + HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"), + HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), + { .ident = NULL } + }; + + if (!dmi_check_system(hdaps_whitelist)) { + printk(KERN_WARNING "hdaps: supported laptop not found!\n"); + ret = -ENXIO; + goto out; + } + + if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) { + ret = -ENXIO; + goto out; + } + + ret = driver_register(&hdaps_driver); + if (ret) + goto out_region; + + pdev = platform_device_register_simple("hdaps", -1, NULL, 0); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + goto out_driver; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group); + if (ret) + goto out_device; + + if (hdaps_mousedev) + hdaps_mousedev_enable(); + + printk(KERN_INFO "hdaps: driver successfully loaded.\n"); + return 0; + +out_device: + platform_device_unregister(pdev); +out_driver: + driver_unregister(&hdaps_driver); +out_region: + release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS); +out: + printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret); + return ret; +} + +static void __exit hdaps_exit(void) +{ + hdaps_mousedev_disable(); + + sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); + platform_device_unregister(pdev); + driver_unregister(&hdaps_driver); + release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS); + + printk(KERN_INFO "hdaps: driver unloaded.\n"); +} + +module_init(hdaps_init); +module_exit(hdaps_exit); + +module_param_named(mousedev, hdaps_mousedev, bool, 0); +MODULE_PARM_DESC(mousedev, "enable the input class device"); + +module_param_named(invert, hdaps_invert, bool, 0); +MODULE_PARM_DESC(invert, "invert data along each axis"); + +MODULE_AUTHOR("Robert Love"); +MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 8610bce0824..21aa9a41f62 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -758,11 +758,6 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, return -ENODEV; } - if (!address) { - dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); - return -ENODEV; - } - s_bridge = pci_dev_get(dev); if (i2c_isa_add_driver(&sis5595_driver)) { pci_dev_put(s_bridge); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 7e699a8ede2..c9cc683eba4 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -2,8 +2,8 @@ smsc47m1.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x - Super-I/O chips. + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, + LPC47M15x and LPC47M192 Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index eb84997627c..05ddc88e7dd 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -812,11 +812,6 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev, return -ENODEV; } - if (!address) { - dev_err(&dev->dev, "No Via 686A sensors found.\n"); - return -ENODEV; - } - s_bridge = pci_dev_get(dev); if (i2c_isa_add_driver(&via686a_driver)) { pci_dev_put(s_bridge); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 02bd5c0239a..3479dc5208e 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -64,6 +64,10 @@ static unsigned short address; /* Insmod parameters */ enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf }; +static int reset; +module_param(reset, bool, 0); +MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); + static int init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); @@ -1279,7 +1283,15 @@ static void w83627hf_init_client(struct i2c_client *client) int type = data->type; u8 tmp; - if(init) { + if (reset) { + /* Resetting the chip has been the default for a long time, + but repeatedly caused problems (fans going to full + speed...) so it is now optional. It might even go away if + nobody reports it as being useful, as I see very little + reason why this would be needed at all. */ + dev_info(&client->dev, "If reset=1 solved a problem you were " + "having, please report!\n"); + /* save this register */ i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); /* Reset all except Watchdog values and last conversion values diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index e0b7a913431..fe9c0f42a2b 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -98,11 +98,6 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_PEC 0x80 -/* Other settings */ -#define MAX_TIMEOUT 256 - - - static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index e11e55dc892..3cbca7cbea8 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -93,7 +93,7 @@ static int dma = 2; static inline void wbsd_unlock_config(struct wbsd_host* host) { BUG_ON(host->config == 0); - + outb(host->unlock_code, host->config); outb(host->unlock_code, host->config); } @@ -101,14 +101,14 @@ static inline void wbsd_unlock_config(struct wbsd_host* host) static inline void wbsd_lock_config(struct wbsd_host* host) { BUG_ON(host->config == 0); - + outb(LOCK_CODE, host->config); } static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) { BUG_ON(host->config == 0); - + outb(reg, host->config); outb(value, host->config + 1); } @@ -116,7 +116,7 @@ static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) { BUG_ON(host->config == 0); - + outb(reg, host->config); return inb(host->config + 1); } @@ -140,21 +140,21 @@ static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index) static void wbsd_init_device(struct wbsd_host* host) { u8 setup, ier; - + /* * Reset chip (SD/MMC part) and fifo. */ setup = wbsd_read_index(host, WBSD_IDX_SETUP); setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET; wbsd_write_index(host, WBSD_IDX_SETUP, setup); - + /* * Set DAT3 to input */ setup &= ~WBSD_DAT3_H; wbsd_write_index(host, WBSD_IDX_SETUP, setup); host->flags &= ~WBSD_FIGNORE_DETECT; - + /* * Read back default clock. */ @@ -164,12 +164,12 @@ static void wbsd_init_device(struct wbsd_host* host) * Power down port. */ outb(WBSD_POWER_N, host->base + WBSD_CSR); - + /* * Set maximum timeout. */ wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); - + /* * Test for card presence */ @@ -177,7 +177,7 @@ static void wbsd_init_device(struct wbsd_host* host) host->flags |= WBSD_FCARD_PRESENT; else host->flags &= ~WBSD_FCARD_PRESENT; - + /* * Enable interesting interrupts. */ @@ -200,9 +200,9 @@ static void wbsd_init_device(struct wbsd_host* host) static void wbsd_reset(struct wbsd_host* host) { u8 setup; - + printk(KERN_ERR DRIVER_NAME ": Resetting chip\n"); - + /* * Soft reset of chip (SD/MMC part). */ @@ -214,9 +214,9 @@ static void wbsd_reset(struct wbsd_host* host) static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq) { unsigned long dmaflags; - + DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode); - + if (host->dma >= 0) { /* @@ -232,7 +232,7 @@ static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq) */ wbsd_write_index(host, WBSD_IDX_DMA, 0); } - + host->mrq = NULL; /* @@ -275,7 +275,7 @@ static inline int wbsd_next_sg(struct wbsd_host* host) host->offset = 0; host->remain = host->cur_sg->length; } - + return host->num_sg; } @@ -297,12 +297,12 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data) struct scatterlist* sg; char* dmabuf = host->dma_buffer; char* sgbuf; - + size = host->size; - + sg = data->sg; len = data->sg_len; - + /* * Just loop through all entries. Size might not * be the entire list though so make sure that @@ -317,23 +317,23 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data) memcpy(dmabuf, sgbuf, sg[i].length); kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); dmabuf += sg[i].length; - + if (size < sg[i].length) size = 0; else size -= sg[i].length; - + if (size == 0) break; } - + /* * Check that we didn't get a request to transfer * more data than can fit into the SG list. */ - + BUG_ON(size != 0); - + host->size -= size; } @@ -343,12 +343,12 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data) struct scatterlist* sg; char* dmabuf = host->dma_buffer; char* sgbuf; - + size = host->size; - + sg = data->sg; len = data->sg_len; - + /* * Just loop through all entries. Size might not * be the entire list though so make sure that @@ -363,30 +363,30 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data) memcpy(sgbuf, dmabuf, sg[i].length); kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); dmabuf += sg[i].length; - + if (size < sg[i].length) size = 0; else size -= sg[i].length; - + if (size == 0) break; } - + /* * Check that we didn't get a request to transfer * more data than can fit into the SG list. */ - + BUG_ON(size != 0); - + host->size -= size; } /* * Command handling */ - + static inline void wbsd_get_short_reply(struct wbsd_host* host, struct mmc_command* cmd) { @@ -398,7 +398,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host* host, cmd->error = MMC_ERR_INVALID; return; } - + cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24; cmd->resp[0] |= @@ -415,7 +415,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, struct mmc_command* cmd) { int i; - + /* * Correct response type? */ @@ -424,7 +424,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, cmd->error = MMC_ERR_INVALID; return; } - + for (i = 0;i < 4;i++) { cmd->resp[i] = @@ -442,7 +442,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) { int i; u8 status, isr; - + DBGF("Sending cmd (%x)\n", cmd->opcode); /* @@ -451,16 +451,16 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) * transfer. */ host->isr = 0; - + /* * Send the command (CRC calculated by host). */ outb(cmd->opcode, host->base + WBSD_CMDR); for (i = 3;i >= 0;i--) outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); - + cmd->error = MMC_ERR_NONE; - + /* * Wait for the request to complete. */ @@ -477,7 +477,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) * Read back status. */ isr = host->isr; - + /* Card removed? */ if (isr & WBSD_INT_CARD) cmd->error = MMC_ERR_TIMEOUT; @@ -509,13 +509,13 @@ static void wbsd_empty_fifo(struct wbsd_host* host) struct mmc_data* data = host->mrq->cmd->data; char* buffer; int i, fsr, fifo; - + /* * Handle excessive data. */ if (data->bytes_xfered == host->size) return; - + buffer = wbsd_kmap_sg(host) + host->offset; /* @@ -527,14 +527,14 @@ static void wbsd_empty_fifo(struct wbsd_host* host) /* * The size field in the FSR is broken so we have to * do some guessing. - */ + */ if (fsr & WBSD_FIFO_FULL) fifo = 16; else if (fsr & WBSD_FIFO_FUTHRE) fifo = 8; else fifo = 1; - + for (i = 0;i < fifo;i++) { *buffer = inb(host->base + WBSD_DFR); @@ -543,23 +543,23 @@ static void wbsd_empty_fifo(struct wbsd_host* host) host->remain--; data->bytes_xfered++; - + /* * Transfer done? */ if (data->bytes_xfered == host->size) { - wbsd_kunmap_sg(host); + wbsd_kunmap_sg(host); return; } - + /* * End of scatter list entry? */ if (host->remain == 0) { wbsd_kunmap_sg(host); - + /* * Get next entry. Check if last. */ @@ -572,17 +572,17 @@ static void wbsd_empty_fifo(struct wbsd_host* host) * into the scatter list. */ BUG_ON(1); - + host->size = data->bytes_xfered; - + return; } - + buffer = wbsd_kmap_sg(host); } } } - + wbsd_kunmap_sg(host); /* @@ -599,7 +599,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) struct mmc_data* data = host->mrq->cmd->data; char* buffer; int i, fsr, fifo; - + /* * Check that we aren't being called after the * entire buffer has been transfered. @@ -618,7 +618,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) /* * The size field in the FSR is broken so we have to * do some guessing. - */ + */ if (fsr & WBSD_FIFO_EMPTY) fifo = 0; else if (fsr & WBSD_FIFO_EMTHRE) @@ -632,9 +632,9 @@ static void wbsd_fill_fifo(struct wbsd_host* host) buffer++; host->offset++; host->remain--; - + data->bytes_xfered++; - + /* * Transfer done? */ @@ -650,7 +650,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) if (host->remain == 0) { wbsd_kunmap_sg(host); - + /* * Get next entry. Check if last. */ @@ -663,19 +663,19 @@ static void wbsd_fill_fifo(struct wbsd_host* host) * into the scatter list. */ BUG_ON(1); - + host->size = data->bytes_xfered; - + return; } - + buffer = wbsd_kmap_sg(host); } } } - + wbsd_kunmap_sg(host); - + /* * The controller stops sending interrupts for * 'FIFO empty' under certain conditions. So we @@ -694,7 +694,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) 1 << data->blksz_bits, data->blocks, data->flags); DBGF("tsac %d ms nsac %d clk\n", data->timeout_ns / 1000000, data->timeout_clks); - + /* * Calculate size. */ @@ -708,12 +708,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) wbsd_write_index(host, WBSD_IDX_TAAC, 127); else wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000); - + if (data->timeout_clks > 255) wbsd_write_index(host, WBSD_IDX_NSAC, 255); else wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks); - + /* * Inform the chip of how large blocks will be * sent. It needs this to determine when to @@ -732,7 +732,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) else if (host->bus_width == MMC_BUS_WIDTH_4) { blksize = (1 << data->blksz_bits) + 2 * 4; - + wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); @@ -751,12 +751,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) setup = wbsd_read_index(host, WBSD_IDX_SETUP); setup |= WBSD_FIFO_RESET; wbsd_write_index(host, WBSD_IDX_SETUP, setup); - + /* * DMA transfer? */ if (host->dma >= 0) - { + { /* * The buffer for DMA is only 64 kB. */ @@ -766,17 +766,17 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) data->error = MMC_ERR_INVALID; return; } - + /* * Transfer data from the SG list to * the DMA buffer. */ if (data->flags & MMC_DATA_WRITE) wbsd_sg_to_dma(host, data); - + /* * Initialise the ISA DMA controller. - */ + */ dmaflags = claim_dma_lock(); disable_dma(host->dma); clear_dma_ff(host->dma); @@ -802,17 +802,17 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) * output to a minimum. */ host->firsterr = 1; - + /* * Initialise the SG list. */ wbsd_init_sg(host, data); - + /* * Turn off DMA. */ wbsd_write_index(host, WBSD_IDX_DMA, 0); - + /* * Set up FIFO threshold levels (and fill * buffer if doing a write). @@ -828,8 +828,8 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) WBSD_FIFOEN_EMPTY | 8); wbsd_fill_fifo(host); } - } - + } + data->error = MMC_ERR_NONE; } @@ -838,7 +838,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) unsigned long dmaflags; int count; u8 status; - + WARN_ON(host->mrq == NULL); /* @@ -855,7 +855,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) { status = wbsd_read_index(host, WBSD_IDX_STATUS); } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE)); - + /* * DMA transfer? */ @@ -865,7 +865,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) * Disable DMA on the host. */ wbsd_write_index(host, WBSD_IDX_DMA, 0); - + /* * Turn of ISA DMA controller. */ @@ -874,7 +874,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) clear_dma_ff(host->dma); count = get_dma_residue(host->dma); release_dma_lock(dmaflags); - + /* * Any leftover data? */ @@ -882,7 +882,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) { printk(KERN_ERR DRIVER_NAME ": Incomplete DMA " "transfer. %d bytes left.\n", count); - + data->error = MMC_ERR_FAILED; } else @@ -893,13 +893,13 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) */ if (data->flags & MMC_DATA_READ) wbsd_dma_to_sg(host, data); - + data->bytes_xfered = host->size; } } - + DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered); - + wbsd_request_end(host, host->mrq); } @@ -924,7 +924,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) cmd = mrq->cmd; host->mrq = mrq; - + /* * If there is no card in the slot then * timeout immediatly. @@ -941,18 +941,18 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) if (cmd->data) { wbsd_prepare_data(host, cmd->data); - + if (cmd->data->error != MMC_ERR_NONE) goto done; } - + wbsd_send_command(host, cmd); /* * If this is a data transfer the request * will be finished after the data has * transfered. - */ + */ if (cmd->data && (cmd->error == MMC_ERR_NONE)) { /* @@ -965,7 +965,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) return; } - + done: wbsd_request_end(host, mrq); @@ -976,7 +976,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct wbsd_host* host = mmc_priv(mmc); u8 clk, setup, pwr; - + DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width); @@ -989,7 +989,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) */ if (ios->power_mode == MMC_POWER_OFF) wbsd_init_device(host); - + if (ios->clock >= 24000000) clk = WBSD_CLK_24M; else if (ios->clock >= 16000000) @@ -1042,7 +1042,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) mod_timer(&host->ignore_timer, jiffies + HZ/100); } wbsd_write_index(host, WBSD_IDX_SETUP, setup); - + /* * Store bus width for later. Will be used when * setting up the data transfer. @@ -1128,7 +1128,7 @@ static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host) WARN_ON(!host->mrq->cmd->data); if (!host->mrq->cmd->data) return NULL; - + return host->mrq->cmd->data; } @@ -1136,72 +1136,67 @@ static void wbsd_tasklet_card(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; u8 csr; - + int delay = -1; + spin_lock(&host->lock); - + if (host->flags & WBSD_FIGNORE_DETECT) { spin_unlock(&host->lock); return; } - + csr = inb(host->base + WBSD_CSR); WARN_ON(csr == 0xff); - + if (csr & WBSD_CARDPRESENT) { if (!(host->flags & WBSD_FCARD_PRESENT)) { DBG("Card inserted\n"); host->flags |= WBSD_FCARD_PRESENT; - - spin_unlock(&host->lock); - /* - * Delay card detection to allow electrical connections - * to stabilise. - */ - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + delay = 500; } - else - spin_unlock(&host->lock); } else if (host->flags & WBSD_FCARD_PRESENT) { DBG("Card removed\n"); host->flags &= ~WBSD_FCARD_PRESENT; - + if (host->mrq) { printk(KERN_ERR DRIVER_NAME ": Card removed during transfer!\n"); wbsd_reset(host); - + host->mrq->cmd->error = MMC_ERR_FAILED; tasklet_schedule(&host->finish_tasklet); } - - /* - * Unlock first since we might get a call back. - */ - spin_unlock(&host->lock); - mmc_detect_change(host->mmc, 0); + delay = 0; } - else - spin_unlock(&host->lock); + + /* + * Unlock first since we might get a call back. + */ + + spin_unlock(&host->lock); + + if (delay != -1) + mmc_detect_change(host->mmc, msecs_to_jiffies(delay)); } static void wbsd_tasklet_fifo(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; struct mmc_data* data; - + spin_lock(&host->lock); - + if (!host->mrq) goto end; - + data = wbsd_get_data(host); if (!data) goto end; @@ -1220,7 +1215,7 @@ static void wbsd_tasklet_fifo(unsigned long param) tasklet_schedule(&host->finish_tasklet); } -end: +end: spin_unlock(&host->lock); } @@ -1228,23 +1223,23 @@ static void wbsd_tasklet_crc(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; struct mmc_data* data; - + spin_lock(&host->lock); - + if (!host->mrq) goto end; - + data = wbsd_get_data(host); if (!data) goto end; - + DBGF("CRC error\n"); data->error = MMC_ERR_BADCRC; - + tasklet_schedule(&host->finish_tasklet); -end: +end: spin_unlock(&host->lock); } @@ -1252,23 +1247,23 @@ static void wbsd_tasklet_timeout(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; struct mmc_data* data; - + spin_lock(&host->lock); - + if (!host->mrq) goto end; - + data = wbsd_get_data(host); if (!data) goto end; - + DBGF("Timeout\n"); data->error = MMC_ERR_TIMEOUT; - + tasklet_schedule(&host->finish_tasklet); -end: +end: spin_unlock(&host->lock); } @@ -1276,20 +1271,20 @@ static void wbsd_tasklet_finish(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; struct mmc_data* data; - + spin_lock(&host->lock); - + WARN_ON(!host->mrq); if (!host->mrq) goto end; - + data = wbsd_get_data(host); if (!data) goto end; wbsd_finish_data(host, data); - -end: + +end: spin_unlock(&host->lock); } @@ -1297,7 +1292,7 @@ static void wbsd_tasklet_block(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; struct mmc_data* data; - + spin_lock(&host->lock); if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) != @@ -1306,15 +1301,15 @@ static void wbsd_tasklet_block(unsigned long param) data = wbsd_get_data(host); if (!data) goto end; - + DBGF("CRC error\n"); data->error = MMC_ERR_BADCRC; - + tasklet_schedule(&host->finish_tasklet); } -end: +end: spin_unlock(&host->lock); } @@ -1326,7 +1321,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) { struct wbsd_host* host = dev_id; int isr; - + isr = inb(host->base + WBSD_ISR); /* @@ -1334,7 +1329,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) */ if (isr == 0xff || isr == 0x00) return IRQ_NONE; - + host->isr |= isr; /* @@ -1352,7 +1347,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) tasklet_hi_schedule(&host->block_tasklet); if (isr & WBSD_INT_TC) tasklet_schedule(&host->finish_tasklet); - + return IRQ_HANDLED; } @@ -1370,14 +1365,14 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) { struct mmc_host* mmc; struct wbsd_host* host; - + /* * Allocate MMC structure. */ mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); if (!mmc) return -ENOMEM; - + host = mmc_priv(mmc); host->mmc = mmc; @@ -1391,37 +1386,37 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; mmc->caps = MMC_CAP_4_BIT_DATA; - + spin_lock_init(&host->lock); - + /* * Set up timers */ init_timer(&host->ignore_timer); host->ignore_timer.data = (unsigned long)host; host->ignore_timer.function = wbsd_reset_ignore; - + /* * Maximum number of segments. Worst case is one sector per segment * so this will be 64kB/512. */ mmc->max_hw_segs = 128; mmc->max_phys_segs = 128; - + /* * Maximum number of sectors in one transfer. Also limited by 64kB * buffer. */ mmc->max_sectors = 128; - + /* * Maximum segment size. Could be one segment with the maximum number * of segments. */ mmc->max_seg_size = mmc->max_sectors * 512; - + dev_set_drvdata(dev, mmc); - + return 0; } @@ -1429,18 +1424,18 @@ static void __devexit wbsd_free_mmc(struct device* dev) { struct mmc_host* mmc; struct wbsd_host* host; - + mmc = dev_get_drvdata(dev); if (!mmc) return; - + host = mmc_priv(mmc); BUG_ON(host == NULL); - + del_timer_sync(&host->ignore_timer); - + mmc_free_host(mmc); - + dev_set_drvdata(dev, NULL); } @@ -1452,7 +1447,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host) { int i, j, k; int id; - + /* * Iterate through all ports, all codes to * find hardware that is in our known list. @@ -1461,32 +1456,32 @@ static int __devinit wbsd_scan(struct wbsd_host* host) { if (!request_region(config_ports[i], 2, DRIVER_NAME)) continue; - + for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++) { id = 0xFFFF; - + outb(unlock_codes[j], config_ports[i]); outb(unlock_codes[j], config_ports[i]); - + outb(WBSD_CONF_ID_HI, config_ports[i]); id = inb(config_ports[i] + 1) << 8; outb(WBSD_CONF_ID_LO, config_ports[i]); id |= inb(config_ports[i] + 1); - + for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++) { if (id == valid_ids[k]) - { + { host->chip_id = id; host->config = config_ports[i]; host->unlock_code = unlock_codes[i]; - + return 0; } } - + if (id != 0xFFFF) { DBG("Unknown hardware (id %x) found at %x\n", @@ -1495,10 +1490,10 @@ static int __devinit wbsd_scan(struct wbsd_host* host) outb(LOCK_CODE, config_ports[i]); } - + release_region(config_ports[i], 2); } - + return -ENODEV; } @@ -1510,12 +1505,12 @@ static int __devinit wbsd_request_region(struct wbsd_host* host, int base) { if (io & 0x7) return -EINVAL; - + if (!request_region(base, 8, DRIVER_NAME)) return -EIO; - + host->base = io; - + return 0; } @@ -1523,12 +1518,12 @@ static void __devexit wbsd_release_regions(struct wbsd_host* host) { if (host->base) release_region(host->base, 8); - + host->base = 0; if (host->config) release_region(host->config, 2); - + host->config = 0; } @@ -1540,10 +1535,10 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) { if (dma < 0) return; - + if (request_dma(dma, DRIVER_NAME)) goto err; - + /* * We need to allocate a special buffer in * order for ISA to be able to DMA to it. @@ -1558,7 +1553,7 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) */ host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); - + /* * ISA DMA must be aligned on a 64k basis. */ @@ -1571,19 +1566,19 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) goto kfree; host->dma = dma; - + return; - + kfree: /* * If we've gotten here then there is some kind of alignment bug */ BUG_ON(1); - + dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); host->dma_addr = (dma_addr_t)NULL; - + kfree(host->dma_buffer); host->dma_buffer = NULL; @@ -1604,7 +1599,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host) kfree(host->dma_buffer); if (host->dma >= 0) free_dma(host->dma); - + host->dma = -1; host->dma_buffer = NULL; host->dma_addr = (dma_addr_t)NULL; @@ -1617,7 +1612,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host) static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) { int ret; - + /* * Allocate interrupt. */ @@ -1625,7 +1620,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); if (ret) return ret; - + host->irq = irq; /* @@ -1637,7 +1632,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); - + return 0; } @@ -1647,9 +1642,9 @@ static void __devexit wbsd_release_irq(struct wbsd_host* host) return; free_irq(host->irq, host); - + host->irq = 0; - + tasklet_kill(&host->card_tasklet); tasklet_kill(&host->fifo_tasklet); tasklet_kill(&host->crc_tasklet); @@ -1666,7 +1661,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host, int base, int irq, int dma) { int ret; - + /* * Allocate I/O ports. */ @@ -1685,7 +1680,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host, * Allocate DMA. */ wbsd_request_dma(host, dma); - + return 0; } @@ -1708,7 +1703,7 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host) { /* * Reset the chip. - */ + */ wbsd_write_config(host, WBSD_CONF_SWRST, 1); wbsd_write_config(host, WBSD_CONF_SWRST, 0); @@ -1716,23 +1711,23 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host) * Select SD/MMC function. */ wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - + /* * Set up card detection. */ wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); - + /* * Configure chip */ wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); - + wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); - + if (host->dma >= 0) wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); - + /* * Enable and power up chip. */ @@ -1743,26 +1738,26 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host) /* * Check that configured resources are correct. */ - + static int __devinit wbsd_chip_validate(struct wbsd_host* host) { int base, irq, dma; - + /* * Select SD/MMC function. */ wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - + /* * Read configuration. */ base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); - + irq = wbsd_read_config(host, WBSD_CONF_IRQ); - + dma = wbsd_read_config(host, WBSD_CONF_DRQ); - + /* * Validate against given configuration. */ @@ -1772,7 +1767,7 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host) return 0; if ((dma != host->dma) && (host->dma != -1)) return 0; - + return 1; } @@ -1788,14 +1783,14 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, struct wbsd_host* host = NULL; struct mmc_host* mmc = NULL; int ret; - + ret = wbsd_alloc_mmc(dev); if (ret) return ret; - + mmc = dev_get_drvdata(dev); host = mmc_priv(mmc); - + /* * Scan for hardware. */ @@ -1814,7 +1809,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, return ret; } } - + /* * Request resources. */ @@ -1825,7 +1820,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, wbsd_free_mmc(dev); return ret; } - + /* * See if chip needs to be configured. */ @@ -1842,7 +1837,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, } else wbsd_chip_config(host); - + /* * Power Management stuff. No idea how this works. * Not tested. @@ -1860,7 +1855,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, * Reset the chip into a known state. */ wbsd_init_device(host); - + mmc_add_host(mmc); printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc)); @@ -1882,12 +1877,12 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp) { struct mmc_host* mmc = dev_get_drvdata(dev); struct wbsd_host* host; - + if (!mmc) return; host = mmc_priv(mmc); - + mmc_remove_host(mmc); if (!pnp) @@ -1900,9 +1895,9 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp) wbsd_write_config(host, WBSD_CONF_ENABLE, 0); wbsd_lock_config(host); } - + wbsd_release_resources(host); - + wbsd_free_mmc(dev); } @@ -1932,7 +1927,7 @@ static int __devinit wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) { int io, irq, dma; - + /* * Get resources from PnP layer. */ @@ -1942,9 +1937,9 @@ wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) dma = pnp_dma(pnpdev, 0); else dma = -1; - + DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); - + return wbsd_init(&pnpdev->dev, io, irq, dma, 1); } @@ -1985,7 +1980,7 @@ static struct device_driver wbsd_driver = { .bus = &platform_bus_type, .probe = wbsd_probe, .remove = wbsd_remove, - + .suspend = wbsd_suspend, .resume = wbsd_resume, }; @@ -2008,7 +2003,7 @@ static struct pnp_driver wbsd_pnp_driver = { static int __init wbsd_drv_init(void) { int result; - + printk(KERN_INFO DRIVER_NAME ": Winbond W83L51xD SD/MMC card interface driver, " DRIVER_VERSION "\n"); @@ -2023,8 +2018,8 @@ static int __init wbsd_drv_init(void) return result; } -#endif /* CONFIG_PNP */ - +#endif /* CONFIG_PNP */ + if (nopnp) { result = driver_register(&wbsd_driver); @@ -2046,13 +2041,13 @@ static void __exit wbsd_drv_exit(void) if (!nopnp) pnp_unregister_driver(&wbsd_pnp_driver); - -#endif /* CONFIG_PNP */ + +#endif /* CONFIG_PNP */ if (nopnp) { platform_device_unregister(wbsd_device); - + driver_unregister(&wbsd_driver); } diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index 9005b5241b3..249baa701cb 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -139,51 +139,50 @@ struct wbsd_host { struct mmc_host* mmc; /* MMC structure */ - + spinlock_t lock; /* Mutex */ int flags; /* Driver states */ #define WBSD_FCARD_PRESENT (1<<0) /* Card is present */ #define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */ - + struct mmc_request* mrq; /* Current request */ - + u8 isr; /* Accumulated ISR */ - + struct scatterlist* cur_sg; /* Current SG entry */ unsigned int num_sg; /* Number of entries left */ void* mapped_sg; /* vaddr of mapped sg */ - + unsigned int offset; /* Offset into current entry */ unsigned int remain; /* Data left in curren entry */ int size; /* Total size of transfer */ - + char* dma_buffer; /* ISA DMA buffer */ dma_addr_t dma_addr; /* Physical address for same */ int firsterr; /* See fifo functions */ - + u8 clk; /* Current clock speed */ unsigned char bus_width; /* Current bus width */ - + int config; /* Config port */ u8 unlock_code; /* Code to unlock config */ int chip_id; /* ID of controller */ - + int base; /* I/O port base */ int irq; /* Interrupt */ int dma; /* DMA channel */ - + struct tasklet_struct card_tasklet; /* Tasklet structures */ struct tasklet_struct fifo_tasklet; struct tasklet_struct crc_tasklet; struct tasklet_struct timeout_tasklet; struct tasklet_struct finish_tasklet; struct tasklet_struct block_tasklet; - - struct timer_list detect_timer; /* Card detection timer */ + struct timer_list ignore_timer; /* Ignore detection timer */ }; diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 811d92e5f5b..cc372136e85 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -25,9 +25,6 @@ /****************************************************************************/ - -/****************************************************************************/ - struct map_info uclinux_ram_map = { .name = "RAM", }; @@ -60,14 +57,15 @@ int __init uclinux_mtd_init(void) struct mtd_info *mtd; struct map_info *mapp; extern char _ebss; + unsigned long addr = (unsigned long) &_ebss; mapp = &uclinux_ram_map; - mapp->phys = (unsigned long) &_ebss; - mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); + mapp->phys = addr; + mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(addr + 8)))); mapp->bankwidth = 4; printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", - (int) mapp->map_priv_2, (int) mapp->size); + (int) mapp->phys, (int) mapp->size); mapp->virt = ioremap_nocache(mapp->phys, mapp->size); @@ -95,7 +93,6 @@ int __init uclinux_mtd_init(void) printk("uclinux[mtd]: set %s to be root filesystem\n", uclinux_romfs[0].name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); - put_mtd_device(mtd); return(0); } @@ -109,7 +106,7 @@ void __exit uclinux_mtd_cleanup(void) map_destroy(uclinux_ram_mtdinfo); uclinux_ram_mtdinfo = NULL; } - if (uclinux_ram_map.map_priv_1) { + if (uclinux_ram_map.virt) { iounmap((void *) uclinux_ram_map.virt); uclinux_ram_map.virt = 0; } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6bb9232514b..54fff9c2e80 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1738,11 +1738,18 @@ config 68360_ENET the Motorola 68360 processor. config FEC - bool "FEC ethernet controller (of ColdFire 5272)" - depends on M5272 || M5282 + bool "FEC ethernet controller (of ColdFire CPUs)" + depends on M523x || M527x || M5272 || M528x help Say Y here if you want to use the built-in 10/100 Fast ethernet - controller on the Motorola ColdFire 5272 processor. + controller on some Motorola ColdFire processors. + +config FEC2 + bool "Second FEC ethernet controller (on some ColdFire CPUs)" + depends on FEC + help + Say Y here if you want to use the second built-in 10/100 Fast + ethernet controller on some Motorola ColdFire processors. config NE_H8300 tristate "NE2000 compatible support for H8/300" diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2c700849137..85504fb900d 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -8,7 +8,7 @@ * describes connections using the internal parallel port I/O, which * is basically all of Port D. * - * Right now, I am very watseful with the buffers. I allocate memory + * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which @@ -19,7 +19,10 @@ * Copyright (c) 2000 Ericsson Radio Systems AB. * * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282. - * Copyrught (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * Copyright (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * + * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) + * Copyright (c) 2004-2005 Macq Electronique SA. */ #include <linux/config.h> @@ -46,7 +49,8 @@ #include <asm/io.h> #include <asm/pgtable.h> -#if defined(CONFIG_M527x) || defined(CONFIG_M5272) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ + defined(CONFIG_M5272) || defined(CONFIG_M528x) #include <asm/coldfire.h> #include <asm/mcfsim.h> #include "fec.h" @@ -71,7 +75,7 @@ static unsigned int fec_hw[] = { #elif defined(CONFIG_M527x) (MCF_MBAR + 0x1000), (MCF_MBAR + 0x1800), -#elif defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M528x) (MCF_MBAR + 0x1000), #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), @@ -94,12 +98,14 @@ static unsigned char fec_mac_default[] = { #define FEC_FLASHMAC 0xffe04000 #elif defined(CONFIG_CANCam) #define FEC_FLASHMAC 0xf0020000 +#elif defined (CONFIG_M5272C3) +#define FEC_FLASHMAC (0xffe04000 + 4) +#elif defined(CONFIG_MOD5272) +#define FEC_FLASHMAC 0xffc0406b #else #define FEC_FLASHMAC 0 #endif -unsigned char *fec_flashmac = (unsigned char *) FEC_FLASHMAC; - /* Forward declarations of some structures to support different PHYs */ @@ -158,7 +164,7 @@ typedef struct { * size bits. Other FEC hardware does not, so we need to take that into * account when setting it. */ -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -196,7 +202,7 @@ struct fec_enet_private { uint phy_id_done; uint phy_status; uint phy_speed; - phy_info_t *phy; + phy_info_t const *phy; struct work_struct phy_task; uint sequence_done; @@ -209,7 +215,6 @@ struct fec_enet_private { int link; int old_link; int full_duplex; - unsigned char mac_addr[ETH_ALEN]; }; static int fec_enet_open(struct net_device *dev); @@ -237,10 +242,10 @@ typedef struct mii_list { } mii_list_t; #define NMII 20 -mii_list_t mii_cmds[NMII]; -mii_list_t *mii_free; -mii_list_t *mii_head; -mii_list_t *mii_tail; +static mii_list_t mii_cmds[NMII]; +static mii_list_t *mii_free; +static mii_list_t *mii_head; +static mii_list_t *mii_tail; static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); @@ -425,7 +430,7 @@ fec_timeout(struct net_device *dev) } } #endif - fec_restart(dev, 0); + fec_restart(dev, fep->full_duplex); netif_wake_queue(dev); } @@ -757,45 +762,52 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); if (mii_reg & 0x0004) - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; if (mii_reg & 0x0010) - *s |= PHY_STAT_FAULT; + status |= PHY_STAT_FAULT; if (mii_reg & 0x0020) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; + + *s = status; } static void mii_parse_cr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP); if (mii_reg & 0x1000) - *s |= PHY_CONF_ANE; + status |= PHY_CONF_ANE; if (mii_reg & 0x4000) - *s |= PHY_CONF_LOOP; + status |= PHY_CONF_LOOP; + *s = status; } static void mii_parse_anar(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_SPMASK); + status = *s & ~(PHY_CONF_SPMASK); if (mii_reg & 0x0020) - *s |= PHY_CONF_10HDX; + status |= PHY_CONF_10HDX; if (mii_reg & 0x0040) - *s |= PHY_CONF_10FDX; + status |= PHY_CONF_10FDX; if (mii_reg & 0x0080) - *s |= PHY_CONF_100HDX; + status |= PHY_CONF_100HDX; if (mii_reg & 0x00100) - *s |= PHY_CONF_100FDX; + status |= PHY_CONF_100FDX; + *s = status; } /* ------------------------------------------------------------------------- */ @@ -811,37 +823,34 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); - + status = *s & ~(PHY_STAT_SPMASK); if (mii_reg & 0x0800) { if (mii_reg & 0x1000) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x1000) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } + *s = status; } -static phy_info_t phy_info_lxt970 = { - 0x07810000, - "LXT970", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_lxt970_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt970_ack_int[] = { /* read SR and ISR to acknowledge */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, @@ -849,11 +858,18 @@ static phy_info_t phy_info_lxt970 = { /* find out the current status */ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt970 = { + .id = 0x07810000, + .name = "LXT970", + .config = phy_cmd_lxt970_config, + .startup = phy_cmd_lxt970_startup, + .ack_int = phy_cmd_lxt970_ack_int, + .shutdown = phy_cmd_lxt970_shutdown }; /* ------------------------------------------------------------------------- */ @@ -878,45 +894,44 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); if (mii_reg & 0x0400) { fep->link = 1; - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; } else { fep->link = 0; } if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x4000) { if (mii_reg & 0x0200) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x0200) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } if (mii_reg & 0x0008) - *s |= PHY_STAT_FAULT; -} + status |= PHY_STAT_FAULT; -static phy_info_t phy_info_lxt971 = { - 0x0001378e, - "LXT971", + *s = status; +} - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board +static phy_cmd_t const phy_cmd_lxt971_config[] = { + /* limit to 10MBit because my prototype board * doesn't work with 100. */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ @@ -925,19 +940,26 @@ static phy_info_t phy_info_lxt971 = { * read here to get a valid value in ack_int */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt971_ack_int[] = { + /* acknowledge the int before reading status ! */ + { mk_mii_read(MII_LXT971_ISR), NULL }, /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, - /* we only need to read ISR to acknowledge */ - { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt971 = { + .id = 0x0001378e, + .name = "LXT971", + .config = phy_cmd_lxt971_config, + .startup = phy_cmd_lxt971_startup, + .ack_int = phy_cmd_lxt971_ack_int, + .shutdown = phy_cmd_lxt971_shutdown }; /* ------------------------------------------------------------------------- */ @@ -956,22 +978,21 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); + status = *s & ~(PHY_STAT_SPMASK); switch((mii_reg >> 2) & 7) { - case 1: *s |= PHY_STAT_10HDX; break; - case 2: *s |= PHY_STAT_100HDX; break; - case 5: *s |= PHY_STAT_10FDX; break; - case 6: *s |= PHY_STAT_100FDX; break; - } + case 1: status |= PHY_STAT_10HDX; break; + case 2: status |= PHY_STAT_100HDX; break; + case 5: status |= PHY_STAT_10FDX; break; + case 6: status |= PHY_STAT_100FDX; break; } -static phy_info_t phy_info_qs6612 = { - 0x00181440, - "QS6612", - - (const phy_cmd_t []) { /* config */ + *s = status; +} + +static phy_cmd_t const phy_cmd_qs6612_config[] = { /* The PHY powers up isolated on the RPX, * so send a command to allow operation. */ @@ -981,13 +1002,13 @@ static phy_info_t phy_info_qs6612 = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_qs6612_ack_int[] = { /* we need to read ISR, SR and ANER to acknowledge */ { mk_mii_read(MII_QS6612_ISR), NULL }, { mk_mii_read(MII_REG_SR), mii_parse_sr }, @@ -996,11 +1017,18 @@ static phy_info_t phy_info_qs6612 = { /* read pcr to get info */ { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_qs6612 = { + .id = 0x00181440, + .name = "QS6612", + .config = phy_cmd_qs6612_config, + .startup = phy_cmd_qs6612_startup, + .ack_int = phy_cmd_qs6612_ack_int, + .shutdown = phy_cmd_qs6612_shutdown }; /* ------------------------------------------------------------------------- */ @@ -1020,49 +1048,54 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x0400) - *s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); else - *s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + + *s = status; } -static phy_info_t phy_info_am79c874 = { - 0x00022561, - "AM79C874", - - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board - * doesn't work with 100. */ +static phy_cmd_t const phy_cmd_am79c874_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_am79c874_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_AM79C874_ICSR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_am79c874 = { + .id = 0x00022561, + .name = "AM79C874", + .config = phy_cmd_am79c874_config, + .startup = phy_cmd_am79c874_startup, + .ack_int = phy_cmd_am79c874_ack_int, + .shutdown = phy_cmd_am79c874_shutdown }; + /* ------------------------------------------------------------------------- */ /* Kendin KS8721BL phy */ @@ -1072,37 +1105,40 @@ static phy_info_t phy_info_am79c874 = { #define MII_KS8721BL_ICSR 22 #define MII_KS8721BL_PHYCR 31 -static phy_info_t phy_info_ks8721bl = { - 0x00022161, - "KS8721BL", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_ks8721bl_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_KS8721BL_ICSR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_ks8721bl = { + .id = 0x00022161, + .name = "KS8721BL", + .config = phy_cmd_ks8721bl_config, + .startup = phy_cmd_ks8721bl_startup, + .ack_int = phy_cmd_ks8721bl_ack_int, + .shutdown = phy_cmd_ks8721bl_shutdown }; /* ------------------------------------------------------------------------- */ -static phy_info_t *phy_info[] = { +static phy_info_t const * const phy_info[] = { &phy_info_lxt970, &phy_info_lxt971, &phy_info_qs6612, @@ -1129,16 +1165,23 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); static void __inline__ fec_request_intrs(struct net_device *dev) { volatile unsigned long *icrp; + static const struct idesc { + char *name; + unsigned short irq; + irqreturn_t (*handler)(int, void *, struct pt_regs *); + } *idp, id[] = { + { "fec(RX)", 86, fec_enet_interrupt }, + { "fec(TX)", 87, fec_enet_interrupt }, + { "fec(OTHER)", 88, fec_enet_interrupt }, + { "fec(MII)", 66, mii_link_interrupt }, + { NULL }, + }; /* Setup interrupt handlers. */ - if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n"); - if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n"); - if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0) - printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n"); - if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate MII IRQ(66)!\n"); + for (idp = id; idp->name; idp++) { + if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq); + } /* Unmask interrupt at ColdFire 5272 SIM */ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3); @@ -1169,17 +1212,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = (unsigned char *)FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1192,14 +1234,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1234,48 +1273,44 @@ static void __inline__ fec_uncache(unsigned long addr) /* ------------------------------------------------------------------------- */ -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* - * Code specific to Coldfire 5270/5271/5274/5275 and 5280/5282 setups. + * Code specific to Coldfire 5230/5231/5232/5234/5235, + * the 5270/5271/5274/5275 and 5280/5282 setups. */ static void __inline__ fec_request_intrs(struct net_device *dev) { struct fec_enet_private *fep; int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 23 }, + { "fec(TXB)", 24 }, + { "fec(TXFIFO)", 25 }, + { "fec(TXCR)", 26 }, + { "fec(RXF)", 27 }, + { "fec(RXB)", 28 }, + { "fec(MII)", 29 }, + { "fec(LC)", 30 }, + { "fec(HBERR)", 31 }, + { "fec(GRA)", 32 }, + { "fec(EBERR)", 33 }, + { "fec(BABT)", 34 }, + { "fec(BABR)", 35 }, + { NULL }, + }; fep = netdev_priv(dev); b = (fep->index) ? 128 : 64; /* Setup interrupt handlers. */ - if (request_irq(b+23, fec_enet_interrupt, 0, "fec(TXF)", dev) != 0) - printk("FEC: Could not allocate FEC(TXF) IRQ(%d+23)!\n", b); - if (request_irq(b+24, fec_enet_interrupt, 0, "fec(TXB)", dev) != 0) - printk("FEC: Could not allocate FEC(TXB) IRQ(%d+24)!\n", b); - if (request_irq(b+25, fec_enet_interrupt, 0, "fec(TXFIFO)", dev) != 0) - printk("FEC: Could not allocate FEC(TXFIFO) IRQ(%d+25)!\n", b); - if (request_irq(b+26, fec_enet_interrupt, 0, "fec(TXCR)", dev) != 0) - printk("FEC: Could not allocate FEC(TXCR) IRQ(%d+26)!\n", b); - - if (request_irq(b+27, fec_enet_interrupt, 0, "fec(RXF)", dev) != 0) - printk("FEC: Could not allocate FEC(RXF) IRQ(%d+27)!\n", b); - if (request_irq(b+28, fec_enet_interrupt, 0, "fec(RXB)", dev) != 0) - printk("FEC: Could not allocate FEC(RXB) IRQ(%d+28)!\n", b); - - if (request_irq(b+29, fec_enet_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate FEC(MII) IRQ(%d+29)!\n", b); - if (request_irq(b+30, fec_enet_interrupt, 0, "fec(LC)", dev) != 0) - printk("FEC: Could not allocate FEC(LC) IRQ(%d+30)!\n", b); - if (request_irq(b+31, fec_enet_interrupt, 0, "fec(HBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(HBERR) IRQ(%d+31)!\n", b); - if (request_irq(b+32, fec_enet_interrupt, 0, "fec(GRA)", dev) != 0) - printk("FEC: Could not allocate FEC(GRA) IRQ(%d+32)!\n", b); - if (request_irq(b+33, fec_enet_interrupt, 0, "fec(EBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(EBERR) IRQ(%d+33)!\n", b); - if (request_irq(b+34, fec_enet_interrupt, 0, "fec(BABT)", dev) != 0) - printk("FEC: Could not allocate FEC(BABT) IRQ(%d+34)!\n", b); - if (request_irq(b+35, fec_enet_interrupt, 0, "fec(BABR)", dev) != 0) - printk("FEC: Could not allocate FEC(BABR) IRQ(%d+35)!\n", b); + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); + } /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */ { @@ -1300,11 +1335,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev) #if defined(CONFIG_M528x) /* Set up gpio outputs for MII lines */ { - volatile unsigned short *gpio_paspar; + volatile u16 *gpio_paspar; + volatile u8 *gpio_pehlpar; - gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR + - 0x100056); - *gpio_paspar = 0x0f00; + gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056); + gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058); + *gpio_paspar |= 0x0f00; + *gpio_pehlpar = 0xc0; } #endif } @@ -1331,17 +1368,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1354,14 +1390,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1392,7 +1425,7 @@ static void __inline__ fec_uncache(unsigned long addr) #else /* - * Code sepcific to the MPC860T setup. + * Code specific to the MPC860T setup. */ static void __inline__ fec_request_intrs(struct net_device *dev) { @@ -1424,13 +1457,10 @@ static void __inline__ fec_request_intrs(struct net_device *dev) static void __inline__ fec_get_mac(struct net_device *dev) { - struct fec_enet_private *fep = netdev_priv(dev); - unsigned char *iap, tmpaddr[6]; bd_t *bd; - int i; - iap = bd->bi_enetaddr; bd = (bd_t *)__res; + memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN); #ifdef CONFIG_RPXCLASSIC /* The Embedded Planet boards have only one MAC address in @@ -1439,14 +1469,8 @@ static void __inline__ fec_get_mac(struct net_device *dev) * the address bits above something that would have (up to * now) been allocated. */ - for (i=0; i<6; i++) - tmpaddr[i] = *iap++; - tmpaddr[3] |= 0x80; - iap = tmpaddr; + dev->dev_adrd[3] |= 0x80; #endif - - for (i=0; i<6; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; } static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) @@ -1556,7 +1580,7 @@ static void mii_display_status(struct net_device *dev) static void mii_display_config(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); + uint status = fep->phy_status; /* ** When we get here, phy_task is already removed from @@ -1565,23 +1589,23 @@ static void mii_display_config(struct net_device *dev) fep->mii_phy_task_queued = 0; printk("%s: config: auto-negotiation ", dev->name); - if (*s & PHY_CONF_ANE) + if (status & PHY_CONF_ANE) printk("on"); else printk("off"); - if (*s & PHY_CONF_100FDX) + if (status & PHY_CONF_100FDX) printk(", 100FDX"); - if (*s & PHY_CONF_100HDX) + if (status & PHY_CONF_100HDX) printk(", 100HDX"); - if (*s & PHY_CONF_10FDX) + if (status & PHY_CONF_10FDX) printk(", 10FDX"); - if (*s & PHY_CONF_10HDX) + if (status & PHY_CONF_10HDX) printk(", 10HDX"); - if (!(*s & PHY_CONF_SPMASK)) + if (!(status & PHY_CONF_SPMASK)) printk(", No speed/duplex selected?"); - if (*s & PHY_CONF_LOOP) + if (status & PHY_CONF_LOOP) printk(", loopback enabled"); printk(".\n"); @@ -1639,7 +1663,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } -/* mii_queue_config is called in user context from fec_enet_open */ +/* mii_queue_config is called in interrupt context from fec_enet_mii */ static void mii_queue_config(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); @@ -1652,14 +1676,14 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } - - -phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, - { mk_mii_end, } }; -phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, - { mk_mii_end, } }; - - +phy_cmd_t const phy_cmd_relink[] = { + { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } + }; +phy_cmd_t const phy_cmd_config[] = { + { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } + }; /* Read remainder of PHY ID. */ @@ -1897,17 +1921,15 @@ static void set_multicast_list(struct net_device *dev) static void fec_set_mac_address(struct net_device *dev) { - struct fec_enet_private *fep; volatile fec_t *fecp; - fep = netdev_priv(dev); - fecp = fep->hwp; + fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); + fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); + fecp->fec_addr_high = (dev->dev_addr[5] << 16) | + (dev->dev_addr[4] << 24); } @@ -1943,7 +1965,7 @@ int __init fec_enet_init(struct net_device *dev) udelay(10); /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc0; + fecp->fec_ievent = 0xffc00000; fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); fecp->fec_hash_table_high = 0; @@ -2063,11 +2085,6 @@ int __init fec_enet_init(struct net_device *dev) /* setup MII interface */ fec_set_mii(dev, fep); - printk("%s: FEC ENET Version 0.2, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ @@ -2106,18 +2123,12 @@ fec_restart(struct net_device *dev, int duplex) /* Clear any outstanding interrupt. */ - fecp->fec_ievent = 0xffc0; + fecp->fec_ievent = 0xffc00000; fec_enable_phy_intr(); /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); - - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i]; + fec_set_mac_address(dev); /* Reset all multicast. */ @@ -2215,7 +2226,7 @@ fec_stop(struct net_device *dev) fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ - while(!(fecp->fec_ievent & 0x10000000)); + while(!(fecp->fec_ievent & FEC_ENET_GRA)); /* Whack a reset. We should wait for this. */ @@ -2234,7 +2245,9 @@ fec_stop(struct net_device *dev) static int __init fec_enet_module_init(void) { struct net_device *dev; - int i, err; + int i, j, err; + + printk("FEC ENET Version 0.2\n"); for (i = 0; (i < FEC_MAX_PORTS); i++) { dev = alloc_etherdev(sizeof(struct fec_enet_private)); @@ -2250,6 +2263,11 @@ static int __init fec_enet_module_init(void) free_netdev(dev); return -EIO; } + + printk("%s: ethernet ", dev->name); + for (j = 0; (j < 5); j++) + printk("%02x:", dev->dev_addr[j]); + printk("%02x\n", dev->dev_addr[5]); } return 0; } diff --git a/drivers/net/fec.h b/drivers/net/fec.h index c6e4f979ff5..045761b8a60 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -1,8 +1,9 @@ /****************************************************************************/ /* - * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5270, - 5271, 5272, 5274, 5275, 5280 and 5282. + * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5230, + * 5231, 5232, 5234, 5235, 5270, 5271, 5272, 5274, 5275, + * 5280 and 5282. * * (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2000-2001, Lineo (www.lineo.com) @@ -13,7 +14,7 @@ #define FEC_H /****************************************************************************/ -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* * Just figures, Motorola would have to change the offsets for * registers in the same peripheral device on different models diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 43b03c55f45..e2ebdcad553 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -63,8 +63,13 @@ struct timer_list mcfrs_timer_struct; #endif #if defined(CONFIG_HW_FEITH) - #define CONSOLE_BAUD_RATE 38400 - #define DEFAULT_CBAUD B38400 +#define CONSOLE_BAUD_RATE 38400 +#define DEFAULT_CBAUD B38400 +#endif + +#if defined(CONFIG_MOD5272) +#define CONSOLE_BAUD_RATE 115200 +#define DEFAULT_CBAUD B115200 #endif #ifndef CONSOLE_BAUD_RATE @@ -90,7 +95,7 @@ static struct tty_driver *mcfrs_serial_driver; #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) #define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) #else #define IRQBASE 73 @@ -1510,7 +1515,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) *portp = (*portp & ~0x000000ff) | 0x00000055; portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); *portp = (*portp & ~0x000003fc) | 0x000002a8; -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c index f8f21567cc2..50858273f8d 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -631,8 +631,10 @@ static void usbin_stop(struct usb_audiodev *as) i = u->flags; spin_unlock_irqrestore(&as->lock, flags); while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { - set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + if (notkilled) + schedule_timeout_interruptible(1); + else + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); @@ -1102,8 +1104,10 @@ static void usbout_stop(struct usb_audiodev *as) i = u->flags; spin_unlock_irqrestore(&as->lock, flags); while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { - set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + if (notkilled) + schedule_timeout_interruptible(1); + else + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 12ecdb03ee5..1017a97a418 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1606,7 +1606,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) return IRQ_NONE; hcd->saw_irq = 1; - if (hcd->state != start && hcd->state == HC_STATE_HALT) + if (hcd->state == HC_STATE_HALT) usb_hc_died (hcd); return IRQ_HANDLED; } @@ -1630,7 +1630,6 @@ void usb_hc_died (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { hcd->poll_rh = 0; - del_timer(&hcd->rh_timer); /* make khubd clean up old urbs and devices */ usb_set_device_state (hcd->self.root_hub, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 758c7f0ed15..a12cab5314e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) static void hub_power_on(struct usb_hub *hub) { int port1; + unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; /* if hub supports power switching, enable power on each port */ if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { @@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub *hub) USB_PORT_FEAT_POWER); } - /* Wait for power to be enabled */ - msleep(hub->descriptor->bPwrOn2PwrGood * 2); + /* Wait at least 100 msec for power to become stable */ + msleep(max(pgood_delay, (unsigned) 100)); } static void hub_quiesce(struct usb_hub *hub) @@ -1460,7 +1461,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, port1, status); else { status = hub_port_wait_reset(hub, port1, udev, delay); - if (status) + if (status && status != -ENOTCONN) dev_dbg(hub->intfdev, "port_wait_reset: err = %d\n", status); @@ -1469,8 +1470,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, /* return on disconnect or reset */ switch (status) { case 0: - /* TRSTRCY = 10 ms */ - msleep(10); + /* TRSTRCY = 10 ms; plus some extra */ + msleep(10 + 40); /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 020815397a4..5c40980a5bd 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -483,6 +483,7 @@ ep_release (struct inode *inode, struct file *fd) data->state = STATE_EP_DISABLED; data->desc.bDescriptorType = 0; data->hs_desc.bDescriptorType = 0; + usb_ep_disable(data->ep); } put_ep (data); return 0; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2507e898af0..b948ffd94f4 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -400,6 +400,23 @@ static int ehci_hc_reset (struct usb_hcd *hcd) return -EIO; } break; + case PCI_VENDOR_ID_NVIDIA: + /* NVidia reports that certain chips don't handle + * QH, ITD, or SITD addresses above 2GB. (But TD, + * data buffer, and periodic schedule are normal.) + */ + switch (pdev->device) { + case 0x003c: /* MCP04 */ + case 0x005b: /* CK804 */ + case 0x00d8: /* CK8 */ + case 0x00e8: /* CK8S */ + if (pci_set_consistent_dma_mask(pdev, + DMA_31BIT_MASK) < 0) + ehci_warn (ehci, "can't enable NVidia " + "workaround for >2GB RAM\n"); + break; + } + break; } /* optional debug port, normally in the first BAR */ @@ -759,12 +776,16 @@ static int ehci_resume (struct usb_hcd *hcd) if (time_before (jiffies, ehci->next_statechange)) msleep (100); - /* If any port is suspended, we know we can/must resume the HC. */ + /* If any port is suspended (or owned by the companion), + * we know we can/must resume the HC (and mustn't reset it). + */ for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { u32 status; port--; status = readl (&ehci->regs->port_status [port]); - if (status & PORT_SUSPEND) { + if (!(status & PORT_POWER)) + continue; + if (status & (PORT_SUSPEND | PORT_OWNER)) { down (&hcd->self.root_hub->serialize); retval = ehci_hub_resume (hcd); up (&hcd->self.root_hub->serialize); @@ -1126,8 +1147,7 @@ rescan: case QH_STATE_UNLINK: /* wait for hw to finish? */ idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (1); + schedule_timeout_uninterruptible(1); goto rescan; case QH_STATE_IDLE: /* fully unlinked */ if (list_empty (&qh->qtd_list)) { diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 36cc1f2218d..18d3f227031 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -54,7 +54,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) /* suspend any active/unsuspended ports, maybe allow wakeup */ while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = readl (reg); + u32 t1 = readl (reg) & ~PORT_RWC_BITS; u32 t2 = t1; if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) @@ -115,7 +115,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd) i = HCS_N_PORTS (ehci->hcs_params); while (i--) { temp = readl (&ehci->regs->port_status [i]); - temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); + temp &= ~(PORT_RWC_BITS + | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); if (temp & PORT_SUSPEND) { ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; @@ -128,7 +129,7 @@ static int ehci_hub_resume (struct usb_hcd *hcd) temp = readl (&ehci->regs->port_status [i]); if ((temp & PORT_SUSPEND) == 0) continue; - temp &= ~PORT_RESUME; + temp &= ~(PORT_RWC_BITS | PORT_RESUME); writel (temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } @@ -191,6 +192,7 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; + port_status &= ~PORT_RWC_BITS; writel (port_status, &ehci->regs->port_status [index]); } else @@ -233,7 +235,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) if (temp & PORT_OWNER) { /* don't report this in GetPortStatus */ if (temp & PORT_CSC) { - temp &= ~PORT_CSC; + temp &= ~PORT_RWC_BITS; + temp |= PORT_CSC; writel (temp, &ehci->regs->port_status [i]); } continue; @@ -343,7 +346,7 @@ static int ehci_hub_control ( &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_ENABLE: - writel (temp | PORT_PEC, + writel((temp & ~PORT_RWC_BITS) | PORT_PEC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_SUSPEND: @@ -353,7 +356,8 @@ static int ehci_hub_control ( if ((temp & PORT_PE) == 0) goto error; /* resume signaling for 20 msec */ - writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME, + temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); + writel (temp | PORT_RESUME, &ehci->regs->port_status [wIndex]); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); @@ -364,15 +368,15 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp & ~PORT_POWER, + writel (temp & ~(PORT_RWC_BITS | PORT_POWER), &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_CONNECTION: - writel (temp | PORT_CSC, + writel((temp & ~PORT_RWC_BITS) | PORT_CSC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_OVER_CURRENT: - writel (temp | PORT_OCC, + writel((temp & ~PORT_RWC_BITS) | PORT_OCC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_RESET: @@ -416,7 +420,7 @@ static int ehci_hub_control ( /* stop resume signaling */ temp = readl (&ehci->regs->port_status [wIndex]); - writel (temp & ~PORT_RESUME, + writel (temp & ~(PORT_RWC_BITS | PORT_RESUME), &ehci->regs->port_status [wIndex]); retval = handshake ( &ehci->regs->port_status [wIndex], @@ -437,7 +441,7 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = 0; /* force reset to complete */ - writel (temp & ~PORT_RESET, + writel (temp & ~(PORT_RWC_BITS | PORT_RESET), &ehci->regs->port_status [wIndex]); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... @@ -500,6 +504,7 @@ static int ehci_hub_control ( if (temp & PORT_OWNER) break; + temp &= ~PORT_RWC_BITS; switch (wValue) { case USB_PORT_FEAT_SUSPEND: if ((temp & PORT_PE) == 0 diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 20c9b550097..f34a0516d35 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -263,6 +263,7 @@ struct ehci_regs { #define PORT_PE (1<<2) /* port enable */ #define PORT_CSC (1<<1) /* connect status change */ #define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) } __attribute__ ((packed)); /* Appendix C, Debug port ... intended for use with special "debug devices" diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 447f488f5d9..7924c74f958 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -228,23 +228,22 @@ ohci_dump_roothub ( char **next, unsigned *size) { - u32 temp, ndp, i; + u32 temp, i; temp = roothub_a (controller); if (temp == ~(u32)0) return; - ndp = (temp & RH_A_NDP); if (verbose) { ohci_dbg_sw (controller, next, size, - "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, + "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp, ((temp & RH_A_POTPGT) >> 24) & 0xff, (temp & RH_A_NOCP) ? " NOCP" : "", (temp & RH_A_OCPM) ? " OCPM" : "", (temp & RH_A_DT) ? " DT" : "", (temp & RH_A_NPS) ? " NPS" : "", (temp & RH_A_PSM) ? " PSM" : "", - ndp + (temp & RH_A_NDP), controller->num_ports ); temp = roothub_b (controller); ohci_dbg_sw (controller, next, size, @@ -266,7 +265,7 @@ ohci_dump_roothub ( ); } - for (i = 0; i < ndp; i++) { + for (i = 0; i < controller->num_ports; i++) { temp = roothub_portstatus (controller, i); dbg_port_sw (controller, i, temp, next, size); } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 56b43f2a0e5..67c1aa5eb1c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -382,8 +382,7 @@ sanitize: goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (1); + schedule_timeout_uninterruptible(1); goto rescan; case ED_IDLE: /* fully unlinked */ if (list_empty (&ed->td_list)) { @@ -485,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci) // flush the writes (void) ohci_readl (ohci, &ohci->regs->control); + /* Read the number of ports unless overridden */ + if (ohci->num_ports == 0) + ohci->num_ports = roothub_a(ohci) & RH_A_NDP; + if (ohci->hcca) return 0; @@ -561,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci) msleep(temp); temp = roothub_a (ohci); if (!(temp & RH_A_NPS)) { - unsigned ports = temp & RH_A_NDP; - /* power down each port */ - for (temp = 0; temp < ports; temp++) + for (temp = 0; temp < ohci->num_ports; temp++) ohci_writel (ohci, RH_PS_LSDA, &ohci->regs->roothub.portstatus [temp]); } @@ -720,6 +721,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) if (ints & OHCI_INTR_RD) { ohci_vdbg (ohci, "resume detect\n"); + ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); if (hcd->state != HC_STATE_QUIESCING) schedule_work(&ohci->rh_resume); } @@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci) * and that if we try to turn them back on the root hub * will respond to CSC processing. */ - i = roothub_a (ohci) & RH_A_NDP; + i = ohci->num_ports; while (i--) ohci_writel (ohci, RH_PS_PSS, &ohci->regs->roothub.portstatus [temp]); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 83ca4549a50..ce7b28da7a1 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) if (status != -EINPROGRESS) return status; - temp = roothub_a (ohci) & RH_A_NDP; + temp = ohci->num_ports; enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, @@ -304,7 +304,7 @@ static int ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ports, i, changed = 0, length = 1; + int i, changed = 0, length = 1; int can_suspend = hcd->can_wakeup; unsigned long flags; @@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) goto done; } - ports = roothub_a (ohci) & RH_A_NDP; - if (ports > MAX_ROOT_PORTS) { - ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, + /* undocumented erratum seen on at least rev D */ + if ((ohci->flags & OHCI_QUIRK_AMD756) + && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { + ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n", ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ goto done; @@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [0] = changed = 1; else buf [0] = 0; - if (ports > 7) { + if (ohci->num_ports > 7) { buf [1] = 0; length++; } /* look at each port */ - for (i = 0; i < ports; i++) { + for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC @@ -395,15 +396,14 @@ ohci_hub_descriptor ( struct usb_hub_descriptor *desc ) { u32 rh = roothub_a (ohci); - int ports = rh & RH_A_NDP; u16 temp; desc->bDescriptorType = 0x29; desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; desc->bHubContrCurrent = 0; - desc->bNbrPorts = ports; - temp = 1 + (ports / 8); + desc->bNbrPorts = ohci->num_ports; + temp = 1 + (ohci->num_ports / 8); desc->bDescLength = 7 + 2 * temp; temp = 0; @@ -421,7 +421,7 @@ ohci_hub_descriptor ( rh = roothub_b (ohci); memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); desc->bitmap [0] = rh & RH_B_DR; - if (ports > 7) { + if (ohci->num_ports > 7) { desc->bitmap [1] = (rh & RH_B_DR) >> 8; desc->bitmap [2] = 0xff; } else diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e5bc1789d18..2fdb262d472 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -75,33 +75,6 @@ static int pxa27x_ohci_select_pmm( int mode ) return 0; } -/* - If you select PMM_PERPORT_MODE, you should set the port power - */ -static int pxa27x_ohci_set_port_power( int port ) -{ - if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) - && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) { - UHCRHPS(port) |= 0x100; - return 0; - } - return -1; -} - -/* - If you select PMM_PERPORT_MODE, you should set the port power - */ -static int pxa27x_ohci_clear_port_power( int port ) -{ - if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) - && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) { - UHCRHPS(port) |= 0x200; - return 0; - } - - return -1; -} - extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ @@ -130,11 +103,17 @@ static void pxa27x_start_hc(struct platform_device *dev) Polarity Low to active low. Supply power to USB ports. */ UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + pxa27x_ohci_pmm_state = PMM_PERPORT_MODE; } UHCHR &= ~UHCHR_SSE; UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE); + + /* Clear any OTG Pin Hold */ + if (PSSR & PSSR_OTGPH) + PSSR |= PSSR_OTGPH; } static void pxa27x_stop_hc(struct platform_device *dev) @@ -198,17 +177,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, pxa27x_start_hc(dev); /* Select Power Management Mode */ - pxa27x_ohci_select_pmm( PMM_PERPORT_MODE ); - - /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */ - if (pxa27x_ohci_set_port_power(1) < 0) - printk(KERN_ERR "Setting port 1 power failed.\n"); - - if (pxa27x_ohci_clear_port_power(2) < 0) - printk(KERN_ERR "Setting port 2 power failed.\n"); - - if (pxa27x_ohci_clear_port_power(3) < 0) - printk(KERN_ERR "Setting port 3 power failed.\n"); + pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -258,6 +227,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd) ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); + /* The value of NDP in roothub_a is incorrect on this hardware */ + ohci->num_ports = 3; + if ((ret = ohci_init(ohci)) < 0) return ret; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 71cdd226286..8a9b9d9209e 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -383,6 +383,7 @@ struct ohci_hcd { /* * driver state */ + int num_ports; int load [NUM_INTS]; u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 0d5d2545bf0..0c024898cbe 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); /* to make sure it doesn't hog all of the bandwidth */ #define DEPTH_INTERVAL 5 -static inline void restart_timer(struct uhci_hcd *uhci) -{ - mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100)); -} - -#include "uhci-hub.c" #include "uhci-debug.c" #include "uhci-q.c" +#include "uhci-hub.c" /* * Make sure the controller is completely inactive, unable to @@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci) { reset_hc(uhci); uhci->hc_inaccessible = 1; - del_timer(&uhci->stall_timer); } /* @@ -287,8 +281,11 @@ __acquires(uhci->lock) /* Enable resume-detect interrupts if they work. * Then enter Global Suspend mode, still configured. */ - int_enable = (resume_detect_interrupts_are_broken(uhci) ? - 0 : USBINTR_RESUME); + uhci->working_RD = 1; + int_enable = USBINTR_RESUME; + if (resume_detect_interrupts_are_broken(uhci)) { + uhci->working_RD = int_enable = 0; + } outw(int_enable, uhci->io_addr + USBINTR); outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); mb(); @@ -315,7 +312,6 @@ __acquires(uhci->lock) uhci->rh_state = new_state; uhci->is_stopped = UHCI_IS_STOPPED; - del_timer(&uhci->stall_timer); uhci_to_hcd(uhci)->poll_rh = !int_enable; uhci_scan_schedule(uhci, NULL); @@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci) mb(); uhci->rh_state = UHCI_RH_RUNNING; uhci_to_hcd(uhci)->poll_rh = 1; - restart_timer(uhci); } static void wakeup_rh(struct uhci_hcd *uhci) @@ -374,20 +369,6 @@ __acquires(uhci->lock) mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); } -static void stall_callback(unsigned long _uhci) -{ - struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci; - unsigned long flags; - - spin_lock_irqsave(&uhci->lock, flags); - uhci_scan_schedule(uhci, NULL); - check_fsbr(uhci); - - if (!uhci->is_stopped) - restart_timer(uhci); - spin_unlock_irqrestore(&uhci->lock, flags); -} - static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -418,8 +399,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) "host controller halted, " "very bad!\n"); hc_died(uhci); - spin_unlock_irqrestore(&uhci->lock, flags); - return IRQ_HANDLED; + + /* Force a callback in case there are + * pending unlinks */ + mod_timer(&hcd->rh_timer, jiffies); } spin_unlock_irqrestore(&uhci->lock, flags); } @@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) if (status & USBSTS_RD) usb_hcd_poll_rh_status(hcd); - - spin_lock_irqsave(&uhci->lock, flags); - uhci_scan_schedule(uhci, regs); - spin_unlock_irqrestore(&uhci->lock, flags); + else { + spin_lock_irqsave(&uhci->lock, flags); + uhci_scan_schedule(uhci, regs); + spin_unlock_irqrestore(&uhci->lock, flags); + } return IRQ_HANDLED; } @@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); - init_timer(&uhci->stall_timer); - uhci->stall_timer.function = stall_callback; - uhci->stall_timer.data = (unsigned long) uhci; - uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), &dma_handle, 0); if (!uhci->fl) { @@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); spin_lock_irq(&uhci->lock); - reset_hc(uhci); + if (!uhci->hc_inaccessible) + reset_hc(uhci); uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); - del_timer_sync(&uhci->stall_timer); release_uhci(uhci); } @@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) */ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); uhci->hc_inaccessible = 1; + hcd->poll_rh = 0; /* FIXME: Enable non-PME# remote wakeup? */ done: spin_unlock_irq(&uhci->lock); - if (rc == 0) - del_timer_sync(&hcd->rh_timer); return rc; } @@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd) spin_unlock_irq(&uhci->lock); - if (hcd->poll_rh) + if (!uhci->working_RD) { + /* Suspended root hub needs to be polled */ + hcd->poll_rh = 1; usb_hcd_poll_rh_status(hcd); + } return 0; } #endif diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index bf9c5f9b508..282f40b7588 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -345,9 +345,6 @@ enum uhci_rh_state { /* * This describes the full uhci information. - * - * Note how the "proper" USB information is just - * a subset of what the full implementation needs. */ struct uhci_hcd { @@ -360,8 +357,6 @@ struct uhci_hcd { struct dma_pool *qh_pool; struct dma_pool *td_pool; - struct usb_bus *bus; - struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ @@ -380,6 +375,8 @@ struct uhci_hcd { unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int need_rescan:1; /* Redo the schedule scan */ unsigned int hc_inaccessible:1; /* HC is suspended or dead */ + unsigned int working_RD:1; /* Suspended root hub doesn't + need to be polled */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ @@ -405,9 +402,7 @@ struct uhci_hcd { /* List of URB's awaiting completion callback */ struct list_head complete_list; /* P: uhci->lock */ - int rh_numports; - - struct timer_list stall_timer; + int rh_numports; /* Number of root-hub ports */ wait_queue_head_t waitqh; /* endpoint_disable waiters */ }; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 4eace2b19dd..a71e48a6680 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - int status; + int status = 0; spin_lock_irqsave(&uhci->lock, flags); - if (uhci->hc_inaccessible) { - status = 0; - goto done; - } + uhci_scan_schedule(uhci, NULL); + if (uhci->hc_inaccessible) + goto done; + check_fsbr(uhci); uhci_check_ports(uhci); + status = get_hub_status_data(uhci, buf); switch (uhci->rh_state) { diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bbb36cd6ed6..ea0d168a8c6 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) { if (uhci->is_stopped) - mod_timer(&uhci->stall_timer, jiffies); + mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); } diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 482c4be521f..1e53934907c 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -286,3 +286,23 @@ config USB_KEYSPAN_REMOTE To compile this driver as a module, choose M here: the module will be called keyspan_remote. + +config USB_APPLETOUCH + tristate "Apple USB Touchpad support" + depends on USB && INPUT + ---help--- + Say Y here if you want to use an Apple USB Touchpad. + + These are the touchpads that can be found on post-February 2005 + Apple Powerbooks (prior models have a Synaptics touchpad connected + to the ADB bus). + + This driver provides a basic mouse driver but can be interfaced + with the synaptics X11 driver to provide acceleration and + scrolling in X11. + + For further information, see + <file:Documentation/input/appletouch.txt>. + + To compile this driver as a module, choose M here: the + module will be called appletouch. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 43b2f999edf..5e03b93f29f 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o +obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c new file mode 100644 index 00000000000..e03c1c567a1 --- /dev/null +++ b/drivers/usb/input/appletouch.c @@ -0,0 +1,469 @@ +/* + * Apple USB Touchpad (for post-February 2005 PowerBooks) driver + * + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) + * Copyright (C) 2005 Stelian Pop (stelian@popies.net) + * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) + * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) + * + * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. + * + * 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 <linux/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/input.h> +#include <linux/usb_input.h> + +/* Apple has powerbooks which have the keyboard with different Product IDs */ +#define APPLE_VENDOR_ID 0x05AC + +#define ATP_DEVICE(prod) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ + .idVendor = APPLE_VENDOR_ID, \ + .idProduct = (prod), \ + .bInterfaceClass = 0x03, \ + .bInterfaceProtocol = 0x02 + +/* table of devices that work with this driver */ +static struct usb_device_id atp_table [] = { + { ATP_DEVICE(0x020E) }, + { ATP_DEVICE(0x020F) }, + { ATP_DEVICE(0x030A) }, + { ATP_DEVICE(0x030B) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, atp_table); + +/* size of a USB urb transfer */ +#define ATP_DATASIZE 81 + +/* + * number of sensors. Note that only 16 instead of 26 X (horizontal) + * sensors exist on 12" and 15" PowerBooks. All models have 16 Y + * (vertical) sensors. + */ +#define ATP_XSENSORS 26 +#define ATP_YSENSORS 16 + +/* amount of fuzz this touchpad generates */ +#define ATP_FUZZ 16 + +/* maximum pressure this driver will report */ +#define ATP_PRESSURE 300 +/* + * multiplication factor for the X and Y coordinates. + * We try to keep the touchpad aspect ratio while still doing only simple + * arithmetics. + * The factors below give coordinates like: + * 0 <= x < 960 on 12" and 15" Powerbooks + * 0 <= x < 1600 on 17" Powerbooks + * 0 <= y < 646 + */ +#define ATP_XFACT 64 +#define ATP_YFACT 43 + +/* + * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is + * ignored. + */ +#define ATP_THRESHOLD 5 + +/* Structure to hold all of our device specific stuff */ +struct atp { + struct usb_device * udev; /* usb device */ + struct urb * urb; /* usb request block */ + signed char * data; /* transferred data */ + int open; /* non-zero if opened */ + struct input_dev input; /* input dev */ + int valid; /* are the sensors valid ? */ + int x_old; /* last reported x/y, */ + int y_old; /* used for smoothing */ + /* current value of the sensors */ + signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; + /* last value of the sensors */ + signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; + /* accumulated sensors */ + int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; +}; + +#define dbg_dump(msg, tab) \ + if (debug > 1) { \ + int i; \ + printk("appletouch: %s %lld", msg, (long long)jiffies); \ + for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ + printk(" %02x", tab[i]); \ + printk("\n"); \ + } + +#define dprintk(format, a...) \ + do { \ + if (debug) printk(format, ##a); \ + } while (0) + +MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold"); +MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); +MODULE_LICENSE("GPL"); + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activate debugging output"); + +static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, + int *z, int *fingers) +{ + int i; + /* values to calculate mean */ + int pcum = 0, psum = 0; + + *fingers = 0; + + for (i = 0; i < nb_sensors; i++) { + if (xy_sensors[i] < ATP_THRESHOLD) + continue; + if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD)) + (*fingers)++; + pcum += xy_sensors[i] * i; + psum += xy_sensors[i]; + } + + if (psum > 0) { + *z = psum; + return pcum * fact / psum; + } + + return 0; +} + +static inline void atp_report_fingers(struct input_dev *input, int fingers) +{ + input_report_key(input, BTN_TOOL_FINGER, fingers == 1); + input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2); + input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); +} + +static void atp_complete(struct urb* urb, struct pt_regs* regs) +{ + int x, y, x_z, y_z, x_f, y_f; + int retval, i; + struct atp *dev = urb->context; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* This urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + /* drop incomplete datasets */ + if (dev->urb->actual_length != ATP_DATASIZE) { + dprintk("appletouch: incomplete data package.\n"); + goto exit; + } + + /* reorder the sensors values */ + for (i = 0; i < 8; i++) { + /* X values */ + dev->xy_cur[i ] = dev->data[5 * i + 2]; + dev->xy_cur[i + 8] = dev->data[5 * i + 4]; + dev->xy_cur[i + 16] = dev->data[5 * i + 42]; + if (i < 2) + dev->xy_cur[i + 24] = dev->data[5 * i + 44]; + + /* Y values */ + dev->xy_cur[i + 26] = dev->data[5 * i + 1]; + dev->xy_cur[i + 34] = dev->data[5 * i + 3]; + } + + dbg_dump("sample", dev->xy_cur); + + if (!dev->valid) { + /* first sample */ + dev->valid = 1; + dev->x_old = dev->y_old = -1; + memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); + + /* 17" Powerbooks have 10 extra X sensors */ + for (i = 16; i < ATP_XSENSORS; i++) + if (dev->xy_cur[i]) { + printk("appletouch: 17\" model detected.\n"); + input_set_abs_params(&dev->input, ABS_X, 0, + (ATP_XSENSORS - 1) * + ATP_XFACT - 1, + ATP_FUZZ, 0); + break; + } + + goto exit; + } + + for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { + /* accumulate the change */ + signed char change = dev->xy_old[i] - dev->xy_cur[i]; + dev->xy_acc[i] -= change; + + /* prevent down drifting */ + if (dev->xy_acc[i] < 0) + dev->xy_acc[i] = 0; + } + + memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); + + dbg_dump("accumulator", dev->xy_acc); + + x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, + ATP_XFACT, &x_z, &x_f); + y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, + ATP_YFACT, &y_z, &y_f); + + if (x && y) { + if (dev->x_old != -1) { + x = (dev->x_old * 3 + x) >> 2; + y = (dev->y_old * 3 + y) >> 2; + dev->x_old = x; + dev->y_old = y; + + if (debug > 1) + printk("appletouch: X: %3d Y: %3d " + "Xz: %3d Yz: %3d\n", + x, y, x_z, y_z); + + input_report_key(&dev->input, BTN_TOUCH, 1); + input_report_abs(&dev->input, ABS_X, x); + input_report_abs(&dev->input, ABS_Y, y); + input_report_abs(&dev->input, ABS_PRESSURE, + min(ATP_PRESSURE, x_z + y_z)); + atp_report_fingers(&dev->input, max(x_f, y_f)); + } + dev->x_old = x; + dev->y_old = y; + } + else if (!x && !y) { + + dev->x_old = dev->y_old = -1; + input_report_key(&dev->input, BTN_TOUCH, 0); + input_report_abs(&dev->input, ABS_PRESSURE, 0); + atp_report_fingers(&dev->input, 0); + + /* reset the accumulator on release */ + memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); + } + + input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]); + + input_sync(&dev->input); + +exit: + retval = usb_submit_urb(dev->urb, GFP_ATOMIC); + if (retval) { + err("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); + } +} + +static int atp_open(struct input_dev *input) +{ + struct atp *dev = input->private; + + if (usb_submit_urb(dev->urb, GFP_ATOMIC)) + return -EIO; + + dev->open = 1; + return 0; +} + +static void atp_close(struct input_dev *input) +{ + struct atp *dev = input->private; + + usb_kill_urb(dev->urb); + dev->open = 0; +} + +static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) +{ + struct atp *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int int_in_endpointAddr = 0; + int i, retval = -ENOMEM; + + /* allocate memory for our device state and initialize it */ + dev = kmalloc(sizeof(struct atp), GFP_KERNEL); + if (dev == NULL) { + err("Out of memory"); + goto err_kmalloc; + } + memset(dev, 0, sizeof(struct atp)); + + dev->udev = interface_to_usbdev(iface); + + /* set up the endpoint information */ + /* use only the first interrupt-in endpoint */ + iface_desc = iface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + endpoint = &iface_desc->endpoint[i].desc; + if (!int_in_endpointAddr && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT)) { + /* we found an interrupt in endpoint */ + int_in_endpointAddr = endpoint->bEndpointAddress; + break; + } + } + if (!int_in_endpointAddr) { + retval = -EIO; + err("Could not find int-in endpoint"); + goto err_endpoint; + } + + /* save our data pointer in this interface device */ + usb_set_intfdata(iface, dev); + + dev->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->urb) { + retval = -ENOMEM; + goto err_usballoc; + } + dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, + &dev->urb->transfer_dma); + if (!dev->data) { + retval = -ENOMEM; + goto err_usbbufalloc; + } + usb_fill_int_urb(dev->urb, dev->udev, + usb_rcvintpipe(dev->udev, int_in_endpointAddr), + dev->data, ATP_DATASIZE, atp_complete, dev, 1); + + init_input_dev(&dev->input); + dev->input.name = "appletouch"; + dev->input.dev = &iface->dev; + dev->input.private = dev; + dev->input.open = atp_open; + dev->input.close = atp_close; + + usb_to_input_id(dev->udev, &dev->input.id); + + set_bit(EV_ABS, dev->input.evbit); + + /* + * 12" and 15" Powerbooks only have 16 x sensors, + * 17" models are detected later. + */ + input_set_abs_params(&dev->input, ABS_X, 0, + (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); + input_set_abs_params(&dev->input, ABS_Y, 0, + (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); + input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); + + set_bit(EV_KEY, dev->input.evbit); + set_bit(BTN_TOUCH, dev->input.keybit); + set_bit(BTN_TOOL_FINGER, dev->input.keybit); + set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit); + set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit); + set_bit(BTN_LEFT, dev->input.keybit); + + input_register_device(&dev->input); + + printk(KERN_INFO "input: appletouch connected\n"); + + return 0; + +err_usbbufalloc: + usb_free_urb(dev->urb); +err_usballoc: + usb_set_intfdata(iface, NULL); +err_endpoint: + kfree(dev); +err_kmalloc: + return retval; +} + +static void atp_disconnect(struct usb_interface *iface) +{ + struct atp *dev = usb_get_intfdata(iface); + + usb_set_intfdata(iface, NULL); + if (dev) { + usb_kill_urb(dev->urb); + input_unregister_device(&dev->input); + usb_free_urb(dev->urb); + usb_buffer_free(dev->udev, ATP_DATASIZE, + dev->data, dev->urb->transfer_dma); + kfree(dev); + } + printk(KERN_INFO "input: appletouch disconnected\n"); +} + +static int atp_suspend(struct usb_interface *iface, pm_message_t message) +{ + struct atp *dev = usb_get_intfdata(iface); + usb_kill_urb(dev->urb); + dev->valid = 0; + return 0; +} + +static int atp_resume(struct usb_interface *iface) +{ + struct atp *dev = usb_get_intfdata(iface); + if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC)) + return -EIO; + + return 0; +} + +static struct usb_driver atp_driver = { + .owner = THIS_MODULE, + .name = "appletouch", + .probe = atp_probe, + .disconnect = atp_disconnect, + .suspend = atp_suspend, + .resume = atp_resume, + .id_table = atp_table, +}; + +static int __init atp_init(void) +{ + return usb_register(&atp_driver); +} + +static void __exit atp_exit(void) +{ + usb_deregister(&atp_driver); +} + +module_init(atp_init); +module_exit(atp_exit); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index e108e0a36b7..a99865c689c 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1446,7 +1446,6 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304 -#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000 /* * Alphabetically sorted blacklist by quirk type. @@ -1465,7 +1464,6 @@ static struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 3957e144caf..7603cbe0865 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -4,11 +4,43 @@ config USB_SISUSBVGA depends on USB && USB_EHCI_HCD ---help--- Say Y here if you intend to attach a USB2VGA dongle based on a - Net2280 and a SiS315 chip. - - Note that this device requires a USB 2.0 host controller. It will not + Net2280 and a SiS315 chip. + + Note that this device requires a USB 2.0 host controller. It will not work with USB 1.x controllers. - To compile this driver as a module, choose M here: the module will be - called sisusb. If unsure, say N. + To compile this driver as a module, choose M here; the module will be + called sisusbvga. If unsure, say N. + +config USB_SISUSBVGA_CON + bool "Text console and mode switching support" if USB_SISUSBVGA + depends on VT + select FONT_8x16 + ---help--- + Say Y here if you want a VGA text console via the USB dongle or + want to support userland applications that utilize the driver's + display mode switching capabilities. + + Note that this console supports VGA/EGA text mode only. + + By default, the console part of the driver will not kick in when + the driver is initialized. If you want the driver to take over + one or more of the consoles, you need to specify the number of + the first and last consoles (starting at 1) as driver parameters. + + For example, if the driver is compiled as a module: + + modprobe sisusbvga first=1 last=5 + + If you use hotplug, add this to your modutils config files with + the "options" keyword, such as eg. + + options sisusbvga first=1 last=5 + + If the driver is compiled into the kernel image, the parameters + must be given in the kernel command like, such as + + sisusbvga.first=1 sisusbvga.last=5 + + diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile index 76f1643ceaf..7f934cfc906 100644 --- a/drivers/usb/misc/sisusbvga/Makefile +++ b/drivers/usb/misc/sisusbvga/Makefile @@ -2,5 +2,7 @@ # Makefile for the sisusb driver (if driver is inside kernel tree). # -obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o +obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o + +sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index d63ce6c030f..39db3155723 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1,6 +1,8 @@ /* * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles * + * Main part + * * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, this code is licensed under the @@ -48,16 +50,60 @@ #include <linux/kref.h> #include <linux/usb.h> #include <linux/smp_lock.h> +#include <linux/vmalloc.h> #include "sisusb.h" +#ifdef INCL_SISUSB_CON +#include <linux/font.h> +#endif + #define SISUSB_DONTSYNC /* Forward declarations / clean-up routines */ +#ifdef INCL_SISUSB_CON +int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); +int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data); +int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data); +int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor); +int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor); +int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand); + +int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data); +int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data); +int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, + u32 dest, int length, size_t *bytes_written); + +int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); + +extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); + +extern void sisusb_init_concode(void); +extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); +extern void sisusb_console_exit(struct sisusb_usb_data *sisusb); + +extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); + +extern int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, + u8 *arg, int cmapsz, int ch512, int dorecalc, + struct vc_data *c, int fh, int uplock); + +static int sisusb_first_vc = 0; +static int sisusb_last_vc = 0; +module_param_named(first, sisusb_first_vc, int, 0); +module_param_named(last, sisusb_last_vc, int, 0); +MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)"); +MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)"); +#endif + static struct usb_driver sisusb_driver; -static DECLARE_MUTEX(disconnect_sem); +DECLARE_MUTEX(disconnect_sem); static void sisusb_free_buffers(struct sisusb_usb_data *sisusb) @@ -639,7 +685,10 @@ static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len, /* The following routines assume being used to transfer byte, word, * long etc. - * This means that they assume "data" in machine endianness format. + * This means that + * - the write routines expect "data" in machine endianness format. + * The data will be converted to leXX in sisusb_xxx_packet. + * - the read routines can expect read data in machine-endianess. */ static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type, @@ -839,7 +888,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (get_user(swap16, (u16 __user *)userbuffer)) return -EFAULT; } else - swap16 = (kernbuffer[0] << 8) | kernbuffer[1]; + swap16 = *((u16 *)kernbuffer); ret = sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, @@ -855,14 +904,25 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (userbuffer) { if (copy_from_user(&buf, userbuffer, 3)) return -EFAULT; - +#ifdef __BIG_ENDIAN swap32 = (buf[0] << 16) | (buf[1] << 8) | buf[2]; +#else + swap32 = (buf[2] << 16) | + (buf[1] << 8) | + buf[0]; +#endif } else +#ifdef __BIG_ENDIAN swap32 = (kernbuffer[0] << 16) | (kernbuffer[1] << 8) | kernbuffer[2]; +#else + swap32 = (kernbuffer[2] << 16) | + (kernbuffer[1] << 8) | + kernbuffer[0]; +#endif ret = sisusb_write_memio_24bit(sisusb, SISUSB_TYPE_MEM, @@ -879,10 +939,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (get_user(swap32, (u32 __user *)userbuffer)) return -EFAULT; } else - swap32 = (kernbuffer[0] << 24) | - (kernbuffer[1] << 16) | - (kernbuffer[2] << 8) | - kernbuffer[3]; + swap32 = *((u32 *)kernbuffer); ret = sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, @@ -1005,6 +1062,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, return ret ? -EIO : 0; } +/* Remember: Read data in packet is in machine-endianess! So for + * byte, word, 24bit, long no endian correction is necessary. + */ + static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type, u32 addr, u8 *data) { @@ -1191,8 +1252,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, (u16 __user *)userbuffer)) return -EFAULT; } else { - kernbuffer[0] = swap16 >> 8; - kernbuffer[1] = swap16 & 0xff; + *((u16 *)kernbuffer) = swap16; } } return ret; @@ -1202,9 +1262,15 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr, &swap32); if (!ret) { (*bytes_read) += 3; +#ifdef __BIG_ENDIAN buf[0] = (swap32 >> 16) & 0xff; buf[1] = (swap32 >> 8) & 0xff; buf[2] = swap32 & 0xff; +#else + buf[2] = (swap32 >> 16) & 0xff; + buf[1] = (swap32 >> 8) & 0xff; + buf[0] = swap32 & 0xff; +#endif if (userbuffer) { if (copy_to_user(userbuffer, &buf[0], 3)) return -EFAULT; @@ -1228,10 +1294,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, userbuffer += 4; } else { - kernbuffer[0] = (swap32 >> 24) & 0xff; - kernbuffer[1] = (swap32 >> 16) & 0xff; - kernbuffer[2] = (swap32 >> 8) & 0xff; - kernbuffer[3] = swap32 & 0xff; + *((u32 *)kernbuffer) = swap32; kernbuffer += 4; } addr += 4; @@ -1289,7 +1352,24 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, /* High level: Gfx (indexed) register access */ -static int +#ifdef INCL_SISUSB_CON +int +sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) +{ + return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); +} + +int +sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data) +{ + return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); +} +#endif + +#ifndef INCL_SISUSB_CON +static +#endif +int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) { int ret; @@ -1298,7 +1378,10 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) return ret; } -static int +#ifndef INCL_SISUSB_CON +static +#endif +int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) { int ret; @@ -1307,7 +1390,10 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) return ret; } -static int +#ifndef INCL_SISUSB_CON +static +#endif +int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor) { @@ -1336,18 +1422,89 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx, return ret; } -static int +#ifndef INCL_SISUSB_CON +static +#endif +int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor) { return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor)); } -static int +#ifndef INCL_SISUSB_CON +static +#endif +int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand) { return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00)); } +/* Write/read video ram */ + +#ifdef INCL_SISUSB_CON +int +sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data) +{ + return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); +} + +int +sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) +{ + return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); +} + +int +sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) +{ + return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); +} + +int +sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) +{ + return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); +} + +int +sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, + u32 dest, int length, size_t *bytes_written) +{ + return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written)); +} + +#ifdef SISUSBENDIANTEST +int +sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, + u32 src, int length, size_t *bytes_written) +{ + return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written)); +} +#endif +#endif + +#ifdef SISUSBENDIANTEST +static void +sisusb_testreadwrite(struct sisusb_usb_data *sisusb) +{ + static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + char destbuffer[10]; + size_t dummy; + int i,j; + + sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); + + for(i = 1; i <= 7; i++) { + printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); + for(j = 0; j < i; j++) { + printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + } + } +} +#endif + /* access pci config registers (reg numbers 0, 4, 8, etc) */ static int @@ -2270,6 +2427,129 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen) return ret; } + +#ifdef INCL_SISUSB_CON + +/* Set up default text mode: + - Set text mode (0x03) + - Upload default font + - Upload user font (if available) +*/ + +int +sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) +{ + int ret = 0, slot = sisusb->font_slot, i; + struct font_desc *myfont; + u8 *tempbuf; + u16 *tempbufb; + size_t written; + static char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer."; + static char bootlogo[] = "(o_ //\\ V_/_"; + + /* sisusb->lock is down */ + + if (!sisusb->SiS_Pr) + return 1; + + sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; + sisusb->SiS_Pr->sisusb = (void *)sisusb; + + /* Set mode 0x03 */ + SiSUSBSetMode(sisusb->SiS_Pr, 0x03); + + if (!(myfont = find_font("VGA8x16"))) + return 1; + + if (!(tempbuf = vmalloc(8192))) + return 1; + + for (i = 0; i < 256; i++) + memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16); + + /* Upload default font */ + ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0); + + vfree(tempbuf); + + /* Upload user font (and reset current slot) */ + if (sisusb->font_backup) { + ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup, + 8192, sisusb->font_backup_512, 1, NULL, + sisusb->font_backup_height, 0); + if (slot != 2) + sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1, + NULL, 16, 0); + } + + if (init && !sisusb->scrbuf) { + + if ((tempbuf = vmalloc(8192))) { + + i = 4096; + tempbufb = (u16 *)tempbuf; + while (i--) + *(tempbufb++) = 0x0720; + + i = 0; + tempbufb = (u16 *)tempbuf; + while (bootlogo[i]) { + *(tempbufb++) = 0x0700 | bootlogo[i++]; + if (!(i % 4)) + tempbufb += 76; + } + + i = 0; + tempbufb = (u16 *)tempbuf + 6; + while (bootstring[i]) + *(tempbufb++) = 0x0700 | bootstring[i++]; + + ret |= sisusb_copy_memory(sisusb, tempbuf, + sisusb->vrambase, 8192, &written); + + vfree(tempbuf); + + } + + } else if (sisusb->scrbuf) { + + ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, + sisusb->vrambase, sisusb->scrbuf_size, &written); + + } + + if (sisusb->sisusb_cursor_size_from >= 0 && + sisusb->sisusb_cursor_size_to >= 0) { + sisusb_setidxreg(sisusb, SISCR, 0x0a, + sisusb->sisusb_cursor_size_from); + sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, + sisusb->sisusb_cursor_size_to); + } else { + sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d); + sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e); + sisusb->sisusb_cursor_size_to = -1; + } + + slot = sisusb->sisusb_cursor_loc; + if(slot < 0) slot = 0; + + sisusb->sisusb_cursor_loc = -1; + sisusb->bad_cursor_pos = 1; + + sisusb_set_cursor(sisusb, slot); + + sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8)); + sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff)); + + sisusb->textmodedestroyed = 0; + + /* sisusb->lock is down */ + + return ret; +} + +#endif + /* fops */ static int @@ -2329,7 +2609,7 @@ sisusb_open(struct inode *inode, struct file *file) } } - /* increment usage count for the device */ + /* Increment usage count for our sisusb */ kref_get(&sisusb->kref); sisusb->isopen = 1; @@ -2340,12 +2620,10 @@ sisusb_open(struct inode *inode, struct file *file) up(&disconnect_sem); - printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor); - return 0; } -static void +void sisusb_delete(struct kref *kref) { struct sisusb_usb_data *sisusb = to_sisusb_dev(kref); @@ -2359,6 +2637,9 @@ sisusb_delete(struct kref *kref) sisusb->sisusb_dev = NULL; sisusb_free_buffers(sisusb); sisusb_free_urbs(sisusb); +#ifdef INCL_SISUSB_CON + kfree(sisusb->SiS_Pr); +#endif kfree(sisusb); } @@ -2395,8 +2676,6 @@ sisusb_release(struct inode *inode, struct file *file) up(&disconnect_sem); - printk(KERN_DEBUG "sisusbvga[%d]: released", myminor); - return 0; } @@ -2733,6 +3012,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, int retval, port, length; u32 address; + /* All our commands require the device + * to be initialized. + */ + if (!sisusb->devinit) + return -ENODEV; + port = y->data3 - SISUSB_PCI_PSEUDO_IOPORTBASE + SISUSB_PCI_IOPORTBASE; @@ -2774,6 +3059,10 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, break; case SUCMD_CLRSCR: + /* Gfx core must be initialized */ + if (!sisusb->gfxinit) + return -ENODEV; + length = (y->data0 << 16) | (y->data1 << 8) | y->data2; address = y->data3 - SISUSB_PCI_PSEUDO_MEMBASE + @@ -2781,11 +3070,61 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, retval = sisusb_clear_vram(sisusb, address, length); break; + case SUCMD_HANDLETEXTMODE: + retval = 0; +#ifdef INCL_SISUSB_CON + /* Gfx core must be initialized, SiS_Pr must exist */ + if (!sisusb->gfxinit || !sisusb->SiS_Pr) + return -ENODEV; + + switch (y->data0) { + case 0: + retval = sisusb_reset_text_mode(sisusb, 0); + break; + case 1: + sisusb->textmodedestroyed = 1; + break; + } +#endif + break; + +#ifdef INCL_SISUSB_CON + case SUCMD_SETMODE: + /* Gfx core must be initialized, SiS_Pr must exist */ + if (!sisusb->gfxinit || !sisusb->SiS_Pr) + return -ENODEV; + + retval = 0; + + sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; + sisusb->SiS_Pr->sisusb = (void *)sisusb; + + if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3)) + retval = -EINVAL; + + break; + + case SUCMD_SETVESAMODE: + /* Gfx core must be initialized, SiS_Pr must exist */ + if (!sisusb->gfxinit || !sisusb->SiS_Pr) + return -ENODEV; + + retval = 0; + + sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; + sisusb->SiS_Pr->sisusb = (void *)sisusb; + + if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3)) + retval = -EINVAL; + + break; +#endif + default: retval = -EINVAL; } - if(retval > 0) + if (retval > 0) retval = -EIO; return retval; @@ -2835,6 +3174,11 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, x.sisusb_vramsize = sisusb->vramsize; x.sisusb_minor = sisusb->minor; x.sisusb_fbdevactive= 0; +#ifdef INCL_SISUSB_CON + x.sisusb_conactive = sisusb->haveconsole ? 1 : 0; +#else + x.sisusb_conactive = 0; +#endif if (copy_to_user((void __user *)arg, &x, sizeof(x))) retval = -EFAULT; @@ -2895,9 +3239,13 @@ static struct file_operations usb_sisusb_fops = { }; static struct usb_class_driver usb_sisusb_class = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) .name = "usb/sisusbvga%d", - .fops = &usb_sisusb_fops, .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, +#else + .name = "sisusbvga%d", +#endif + .fops = &usb_sisusb_fops, .minor_base = SISUSB_MINOR }; @@ -2994,12 +3342,25 @@ static int sisusb_probe(struct usb_interface *intf, printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", sisusb->minor, sisusb->numobufs); +#ifdef INCL_SISUSB_CON + /* Allocate our SiS_Pr */ + if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { + printk(KERN_ERR + "sisusbvga[%d]: Failed to allocate SiS_Pr\n", + sisusb->minor); + } +#endif + /* Do remaining init stuff */ init_waitqueue_head(&sisusb->wait_q); usb_set_intfdata(intf, sisusb); + usb_get_dev(sisusb->sisusb_dev); + + sisusb->present = 1; + #ifdef SISUSB_OLD_CONFIG_COMPAT { int ret; @@ -3014,14 +3375,19 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->minor); else sisusb->ioctl32registered = 1; - } #endif - sisusb->present = 1; - if (dev->speed == USB_SPEED_HIGH) { - if (sisusb_init_gfxdevice(sisusb, 1)) + int initscreen = 1; +#ifdef INCL_SISUSB_CON + if (sisusb_first_vc > 0 && + sisusb_last_vc > 0 && + sisusb_first_vc <= sisusb_last_vc && + sisusb_last_vc <= MAX_NR_CONSOLES) + initscreen = 0; +#endif + if (sisusb_init_gfxdevice(sisusb, initscreen)) printk(KERN_ERR "sisusbvga[%d]: Failed to early " "initialize device\n", @@ -3035,6 +3401,16 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ready = 1; +#ifdef SISUSBENDIANTEST + printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + sisusb_testreadwrite(sisusb); + printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); +#endif + +#ifdef INCL_SISUSB_CON + sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc); +#endif + return 0; error_4: @@ -3053,13 +3429,20 @@ static void sisusb_disconnect(struct usb_interface *intf) struct sisusb_usb_data *sisusb; int minor; - down(&disconnect_sem); - /* This should *not* happen */ - if (!(sisusb = usb_get_intfdata(intf))) { - up(&disconnect_sem); + if (!(sisusb = usb_get_intfdata(intf))) return; - } + +#ifdef INCL_SISUSB_CON + sisusb_console_exit(sisusb); +#endif + + /* The above code doesn't need the disconnect + * semaphore to be down; its meaning is to + * protect all other routines from the disconnect + * case, not the other way round. + */ + down(&disconnect_sem); down(&sisusb->lock); @@ -3123,11 +3506,17 @@ static int __init usb_sisusb_init(void) { int retval; +#ifdef INCL_SISUSB_CON + sisusb_init_concode(); +#endif + if (!(retval = usb_register(&sisusb_driver))) { + printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); printk(KERN_INFO "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); + } return retval; @@ -3142,6 +3531,6 @@ module_init(usb_sisusb_init); module_exit(usb_sisusb_exit); MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>"); -MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles"); +MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 1306d006a25..401ff21d788 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -46,15 +46,36 @@ #endif #endif +/* For older kernels, support for text consoles is by default + * off. To ensable text console support, change the following: + */ +#if 0 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) +#define CONFIG_USB_SISUSBVGA_CON +#endif +#endif + /* Version Information */ #define SISUSB_VERSION 0 #define SISUSB_REVISION 0 -#define SISUSB_PATCHLEVEL 7 +#define SISUSB_PATCHLEVEL 8 + +/* Include console and mode switching code? */ + +#ifdef CONFIG_USB_SISUSBVGA_CON +#define INCL_SISUSB_CON 1 +#endif + +#ifdef INCL_SISUSB_CON +#include <linux/console.h> +#include <linux/vt_kern.h> +#include "sisusb_struct.h" +#endif /* USB related */ -#define SISUSB_MINOR 133 /* FIXME */ +#define SISUSB_MINOR 133 /* official */ /* Size of the sisusb input/output buffers */ #define SISUSB_IBUF_SIZE 0x01000 @@ -131,6 +152,26 @@ struct sisusb_usb_data { unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; +#ifdef INCL_SISUSB_CON + struct SiS_Private *SiS_Pr; + unsigned long scrbuf; + unsigned int scrbuf_size; + int haveconsole, con_first, con_last; + int havethisconsole[MAX_NR_CONSOLES]; + int textmodedestroyed; + unsigned int sisusb_num_columns; /* real number, not vt's idea */ + int cur_start_addr, con_rolled_over; + int sisusb_cursor_loc, bad_cursor_pos; + int sisusb_cursor_size_from; + int sisusb_cursor_size_to; + int current_font_height, current_font_512; + int font_backup_size, font_backup_height, font_backup_512; + char *font_backup; + int font_slot; + struct vc_data *sisusb_display_fg; + int is_gfx; + int con_blanked; +#endif }; #define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref) @@ -249,7 +290,9 @@ struct sisusb_info { __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u8 sisusb_reserved[32]; /* for future use */ + __u32 sisusb_conactive; /* != 0 if console driver active */ + + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { @@ -261,18 +304,24 @@ struct sisusb_command { __u32 data4; /* for future use */ }; -#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ -#define SUCMD_SET 0x02 /* data1 = value */ -#define SUCMD_SETOR 0x03 /* data1 = or */ -#define SUCMD_SETAND 0x04 /* data1 = and */ -#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */ -#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */ +#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ +#define SUCMD_SET 0x02 /* data1 = value */ +#define SUCMD_SETOR 0x03 /* data1 = or */ +#define SUCMD_SETAND 0x04 /* data1 = and */ +#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */ +#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */ -#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ +#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ + +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ + +#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ +#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ #define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command) -#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) -#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) +#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) +#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) + #endif /* SISUSB_H */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c new file mode 100644 index 00000000000..24584463553 --- /dev/null +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -0,0 +1,1658 @@ +/* + * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles + * + * VGA text mode console part + * + * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, this code is licensed under the + * terms of the GPL v2. + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific psisusbr written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + * Portions based on vgacon.c which are + * Created 28 Sep 1997 by Geert Uytterhoeven + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * based on code Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * + * A note on using in_atomic() in here: We can't handle console + * calls from non-schedulable context due to our USB-dependend + * nature. For now, this driver just ignores any calls if it + * detects this state. + * + */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/spinlock.h> +#include <linux/kref.h> +#include <linux/smp_lock.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> + +#include "sisusb.h" + +#ifdef INCL_SISUSB_CON +extern int sisusb_setreg(struct sisusb_usb_data *, int, u8); +extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *); +extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8); +extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *); +extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8); +extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8); +extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8); + +extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); +extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data); +extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data); +extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, + u32 dest, int length, size_t *bytes_written); + +extern void sisusb_delete(struct kref *kref); +extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); + +extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); + +#define sisusbcon_writew(val, addr) (*(addr) = (val)) +#define sisusbcon_readw(addr) (*(addr)) +#define sisusbcon_memmovew(d, s, c) memmove(d, s, c) +#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c) + +/* vc_data -> sisusb conversion table */ +static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; + +/* Forward declaration */ +static const struct consw sisusb_con; + +extern struct semaphore disconnect_sem; + +static inline void +sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) +{ + count /= 2; + while (count--) + sisusbcon_writew(c, s++); +} + +static inline void +sisusb_initialize(struct sisusb_usb_data *sisusb) +{ + /* Reset cursor and start address */ + if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00)) + return; + if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00)) + return; + if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00)) + return; + sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00); +} + +static inline void +sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c) +{ + sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2; + + sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8)); + sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff)); +} + +void +sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location) +{ + if (sisusb->sisusb_cursor_loc == location) + return; + + sisusb->sisusb_cursor_loc = location; + + /* Hardware bug: Text cursor appears twice or not at all + * at some positions. Work around it with the cursor skew + * bits. + */ + + if ((location & 0x0007) == 0x0007) { + sisusb->bad_cursor_pos = 1; + location--; + if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20)) + return; + } else if (sisusb->bad_cursor_pos) { + if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f)) + return; + sisusb->bad_cursor_pos = 0; + } + + if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8))) + return; + sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff)); +} + +static inline struct sisusb_usb_data * +sisusb_get_sisusb(unsigned short console) +{ + return mysisusbs[console]; +} + +static inline int +sisusb_sisusb_valid(struct sisusb_usb_data *sisusb) +{ + if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) + return 0; + + return 1; +} + +static struct sisusb_usb_data * +sisusb_get_sisusb_lock_and_check(unsigned short console) +{ + struct sisusb_usb_data *sisusb; + + /* We can't handle console calls in non-schedulable + * context due to our locks and the USB transport. + * So we simply ignore them. This should only affect + * some calls to printk. + */ + if (in_atomic()) + return NULL; + + if (!(sisusb = sisusb_get_sisusb(console))) + return NULL; + + down(&sisusb->lock); + + if (!sisusb_sisusb_valid(sisusb) || + !sisusb->havethisconsole[console]) { + up(&sisusb->lock); + return NULL; + } + + return sisusb; +} + +static int +sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb) +{ + if (sisusb->is_gfx || + sisusb->textmodedestroyed || + c->vc_mode != KD_TEXT) + return 1; + + return 0; +} + +/* con_startup console interface routine */ +static const char * +sisusbcon_startup(void) +{ + return "SISUSBCON"; +} + +/* con_init console interface routine */ +static void +sisusbcon_init(struct vc_data *c, int init) +{ + struct sisusb_usb_data *sisusb; + int cols, rows; + + /* This is called by take_over_console(), + * ie by us/under our control. It is + * only called after text mode and fonts + * are set up/restored. + */ + + down(&disconnect_sem); + + if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { + up(&disconnect_sem); + return; + } + + down(&sisusb->lock); + + if (!sisusb_sisusb_valid(sisusb)) { + up(&sisusb->lock); + up(&disconnect_sem); + return; + } + + c->vc_can_do_color = 1; + + c->vc_complement_mask = 0x7700; + + c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0; + + sisusb->haveconsole = 1; + + sisusb->havethisconsole[c->vc_num] = 1; + + /* We only support 640x400 */ + c->vc_scan_lines = 400; + + c->vc_font.height = sisusb->current_font_height; + + /* We only support width = 8 */ + cols = 80; + rows = c->vc_scan_lines / c->vc_font.height; + + /* Increment usage count for our sisusb. + * Doing so saves us from upping/downing + * the disconnect semaphore; we can't + * lose our sisusb until this is undone + * in con_deinit. For all other console + * interface functions, it suffices to + * use sisusb->lock and do a quick check + * of sisusb for device disconnection. + */ + kref_get(&sisusb->kref); + + if (!*c->vc_uni_pagedir_loc) + con_set_default_unimap(c); + + up(&sisusb->lock); + + up(&disconnect_sem); + + if (init) { + c->vc_cols = cols; + c->vc_rows = rows; + } else + vc_resize(c, cols, rows); +} + +/* con_deinit console interface routine */ +static void +sisusbcon_deinit(struct vc_data *c) +{ + struct sisusb_usb_data *sisusb; + int i; + + /* This is called by take_over_console() + * and others, ie not under our control. + */ + + down(&disconnect_sem); + + if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { + up(&disconnect_sem); + return; + } + + down(&sisusb->lock); + + /* Clear ourselves in mysisusbs */ + mysisusbs[c->vc_num] = NULL; + + sisusb->havethisconsole[c->vc_num] = 0; + + /* Free our font buffer if all consoles are gone */ + if (sisusb->font_backup) { + for(i = 0; i < MAX_NR_CONSOLES; i++) { + if (sisusb->havethisconsole[c->vc_num]) + break; + } + if (i == MAX_NR_CONSOLES) { + vfree(sisusb->font_backup); + sisusb->font_backup = NULL; + } + } + + up(&sisusb->lock); + + /* decrement the usage count on our sisusb */ + kref_put(&sisusb->kref, sisusb_delete); + + up(&disconnect_sem); +} + +/* interface routine */ +static u8 +sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity, + u8 blink, u8 underline, u8 reverse) +{ + u8 attr = color; + + if (underline) + attr = (attr & 0xf0) | c->vc_ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | c->vc_halfcolor; + + if (reverse) + attr = ((attr) & 0x88) | + ((((attr) >> 4) | + ((attr) << 4)) & 0x77); + + if (blink) + attr ^= 0x80; + + if (intensity == 2) + attr ^= 0x08; + + return attr; +} + +/* Interface routine */ +static void +sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count) +{ + /* Invert a region. This is called with a pointer + * to the console's internal screen buffer. So we + * simply do the inversion there and rely on + * a call to putc(s) to update the real screen. + */ + + while (count--) { + u16 a = sisusbcon_readw(p); + + a = ((a) & 0x88ff) | + (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); + + sisusbcon_writew(a, p++); + } +} + +#define SISUSB_VADDR(x,y) \ + ((u16 *)c->vc_origin + \ + (y) * sisusb->sisusb_num_columns + \ + (x)) + +#define SISUSB_HADDR(x,y) \ + ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \ + (y) * sisusb->sisusb_num_columns + \ + (x)) + +/* Interface routine */ +static void +sisusbcon_putc(struct vc_data *c, int ch, int y, int x) +{ + struct sisusb_usb_data *sisusb; + ssize_t written; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + /* Don't need to put the character into buffer ourselves, + * because the vt does this BEFORE calling us. + */ +#if 0 + sisusbcon_writew(ch, SISUSB_VADDR(x, y)); +#endif + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + + sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), + (u32)SISUSB_HADDR(x, y), 2, &written); + + up(&sisusb->lock); +} + +/* Interface routine */ +static void +sisusbcon_putcs(struct vc_data *c, const unsigned short *s, + int count, int y, int x) +{ + struct sisusb_usb_data *sisusb; + ssize_t written; + u16 *dest; + int i; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + /* Need to put the characters into the buffer ourselves, + * because the vt does this AFTER calling us. + */ + + dest = SISUSB_VADDR(x, y); + + for (i = count; i > 0; i--) + sisusbcon_writew(sisusbcon_readw(s++), dest++); + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), + (u32)SISUSB_HADDR(x, y), count * 2, &written); + + up(&sisusb->lock); +} + +/* Interface routine */ +static void +sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) +{ + struct sisusb_usb_data *sisusb; + u16 eattr = c->vc_video_erase_char; + ssize_t written; + int i, length, cols; + u16 *dest; + + if (width <= 0 || height <= 0) + return; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + /* Need to clear buffer ourselves, because the vt does + * this AFTER calling us. + */ + + dest = SISUSB_VADDR(x, y); + + cols = sisusb->sisusb_num_columns; + + if (width > cols) + width = cols; + + if (x == 0 && width >= c->vc_cols) { + + sisusbcon_memsetw(dest, eattr, height * cols * 2); + + } else { + + for (i = height; i > 0; i--, dest += cols) + sisusbcon_memsetw(dest, eattr, width * 2); + + } + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + length = ((height * cols) - x - (cols - width - x)) * 2; + + + sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), + (u32)SISUSB_HADDR(x, y), length, &written); + + up(&sisusb->lock); +} + +/* Interface routine */ +static void +sisusbcon_bmove(struct vc_data *c, int sy, int sx, + int dy, int dx, int height, int width) +{ + struct sisusb_usb_data *sisusb; + ssize_t written; + int cols, length; +#if 0 + u16 *src, *dest; + int i; +#endif + + if (width <= 0 || height <= 0) + return; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + cols = sisusb->sisusb_num_columns; + + /* Don't need to move data outselves, because + * vt does this BEFORE calling us. + * This is only used by vt's insert/deletechar. + */ +#if 0 + if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { + + sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), + height * width * 2); + + } else if (dy < sy || (dy == sy && dx < sx)) { + + src = SISUSB_VADDR(sx, sy); + dest = SISUSB_VADDR(dx, dy); + + for (i = height; i > 0; i--) { + sisusbcon_memmovew(dest, src, width * 2); + src += cols; + dest += cols; + } + + } else { + + src = SISUSB_VADDR(sx, sy + height - 1); + dest = SISUSB_VADDR(dx, dy + height - 1); + + for (i = height; i > 0; i--) { + sisusbcon_memmovew(dest, src, width * 2); + src -= cols; + dest -= cols; + } + + } +#endif + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + length = ((height * cols) - dx - (cols - width - dx)) * 2; + + + sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), + (u32)SISUSB_HADDR(dx, dy), length, &written); + + up(&sisusb->lock); +} + +/* interface routine */ +static int +sisusbcon_switch(struct vc_data *c) +{ + struct sisusb_usb_data *sisusb; + ssize_t written; + int length; + + /* Returnvalue 0 means we have fully restored screen, + * and vt doesn't need to call do_update_region(). + * Returnvalue != 0 naturally means the opposite. + */ + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return 0; + + /* sisusb->lock is down */ + + /* Don't write to screen if in gfx mode */ + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return 0; + } + + /* That really should not happen. It would mean we are + * being called while the vc is using its private buffer + * as origin. + */ + if (c->vc_origin == (unsigned long)c->vc_screenbuf) { + up(&sisusb->lock); + printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + return 0; + } + + /* Check that we don't copy too much */ + length = min((int)c->vc_screenbuf_size, + (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); + + /* Restore the screen contents */ + sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, + length); + + sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, + (u32)SISUSB_HADDR(0, 0), + length, &written); + + up(&sisusb->lock); + + return 0; +} + +/* interface routine */ +static void +sisusbcon_save_screen(struct vc_data *c) +{ + struct sisusb_usb_data *sisusb; + int length; + + /* Save the current screen contents to vc's private + * buffer. + */ + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + /* Check that we don't copy too much */ + length = min((int)c->vc_screenbuf_size, + (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); + + /* Save the screen contents to vc's private buffer */ + sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, + length); + + up(&sisusb->lock); +} + +/* interface routine */ +static int +sisusbcon_set_palette(struct vc_data *c, unsigned char *table) +{ + struct sisusb_usb_data *sisusb; + int i, j; + + /* Return value not used by vt */ + + if (!CON_IS_VISIBLE(c)) + return -EINVAL; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return -EINVAL; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return -EINVAL; + } + + for (i = j = 0; i < 16; i++) { + if (sisusb_setreg(sisusb, SISCOLIDX, table[i])) + break; + if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) + break; + if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) + break; + if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) + break; + } + + up(&sisusb->lock); + + return 0; +} + +/* interface routine */ +static int +sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) +{ + struct sisusb_usb_data *sisusb; + u8 sr1, cr17, pmreg, cr63; + ssize_t written; + int ret = 0; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return 0; + + /* sisusb->lock is down */ + + if (mode_switch) + sisusb->is_gfx = blank ? 1 : 0; + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return 0; + } + + switch (blank) { + + case 1: /* Normal blanking: Clear screen */ + case -1: + sisusbcon_memsetw((u16 *)c->vc_origin, + c->vc_video_erase_char, + c->vc_screenbuf_size); + sisusb_copy_memory(sisusb, + (unsigned char *)c->vc_origin, + (u32)(sisusb->vrambase + + (c->vc_origin - sisusb->scrbuf)), + c->vc_screenbuf_size, &written); + sisusb->con_blanked = 1; + ret = 1; + break; + + default: /* VESA blanking */ + switch (blank) { + case 0: /* Unblank */ + sr1 = 0x00; + cr17 = 0x80; + pmreg = 0x00; + cr63 = 0x00; + ret = 1; + sisusb->con_blanked = 0; + break; + case VESA_VSYNC_SUSPEND + 1: + sr1 = 0x20; + cr17 = 0x80; + pmreg = 0x80; + cr63 = 0x40; + break; + case VESA_HSYNC_SUSPEND + 1: + sr1 = 0x20; + cr17 = 0x80; + pmreg = 0x40; + cr63 = 0x40; + break; + case VESA_POWERDOWN + 1: + sr1 = 0x20; + cr17 = 0x00; + pmreg = 0xc0; + cr63 = 0x40; + break; + default: + up(&sisusb->lock); + return -EINVAL; + } + + sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1); + sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17); + sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg); + sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63); + + } + + up(&sisusb->lock); + + return ret; +} + +/* interface routine */ +static int +sisusbcon_scrolldelta(struct vc_data *c, int lines) +{ + struct sisusb_usb_data *sisusb; + int margin = c->vc_size_row * 4; + int ul, we, p, st; + + /* The return value does not seem to be used */ + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return 0; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return 0; + } + + if (!lines) /* Turn scrollback off */ + c->vc_visible_origin = c->vc_origin; + else { + + if (sisusb->con_rolled_over > + (c->vc_scr_end - sisusb->scrbuf) + margin) { + + ul = c->vc_scr_end - sisusb->scrbuf; + we = sisusb->con_rolled_over + c->vc_size_row; + + } else { + + ul = 0; + we = sisusb->scrbuf_size; + + } + + p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we + + lines * c->vc_size_row; + + st = (c->vc_origin - sisusb->scrbuf - ul + we) % we; + + if (st < 2 * margin) + margin = 0; + + if (p < margin) + p = 0; + + if (p > st - margin) + p = st; + + c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we; + } + + sisusbcon_set_start_address(sisusb, c); + + up(&sisusb->lock); + + return 1; +} + +/* Interface routine */ +static void +sisusbcon_cursor(struct vc_data *c, int mode) +{ + struct sisusb_usb_data *sisusb; + int from, to, baseline; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return; + } + + if (c->vc_origin != c->vc_visible_origin) { + c->vc_visible_origin = c->vc_origin; + sisusbcon_set_start_address(sisusb, c); + } + + if (mode == CM_ERASE) { + sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20); + sisusb->sisusb_cursor_size_to = -1; + up(&sisusb->lock); + return; + } + + sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2); + + baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2); + + switch (c->vc_cursor_type & 0x0f) { + case CUR_BLOCK: from = 1; + to = c->vc_font.height; + break; + case CUR_TWO_THIRDS: from = c->vc_font.height / 3; + to = baseline; + break; + case CUR_LOWER_HALF: from = c->vc_font.height / 2; + to = baseline; + break; + case CUR_LOWER_THIRD: from = (c->vc_font.height * 2) / 3; + to = baseline; + break; + case CUR_NONE: from = 31; + to = 30; + break; + default: + case CUR_UNDERLINE: from = baseline - 1; + to = baseline; + break; + } + + if (sisusb->sisusb_cursor_size_from != from || + sisusb->sisusb_cursor_size_to != to) { + + sisusb_setidxreg(sisusb, SISCR, 0x0a, from); + sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to); + + sisusb->sisusb_cursor_size_from = from; + sisusb->sisusb_cursor_size_to = to; + } + + up(&sisusb->lock); +} + +static int +sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, + int t, int b, int dir, int lines) +{ + int cols = sisusb->sisusb_num_columns; + int length = ((b - t) * cols) * 2; + u16 eattr = c->vc_video_erase_char; + ssize_t written; + + /* sisusb->lock is down */ + + /* Scroll an area which does not match the + * visible screen's dimensions. This needs + * to be done separately, as it does not + * use hardware panning. + */ + + switch (dir) { + + case SM_UP: + sisusbcon_memmovew(SISUSB_VADDR(0, t), + SISUSB_VADDR(0, t + lines), + (b - t - lines) * cols * 2); + sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr, + lines * cols * 2); + break; + + case SM_DOWN: + sisusbcon_memmovew(SISUSB_VADDR(0, t + lines), + SISUSB_VADDR(0, t), + (b - t - lines) * cols * 2); + sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr, + lines * cols * 2); + break; + } + + sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), + (u32)SISUSB_HADDR(0, t), length, &written); + + up(&sisusb->lock); + + return 1; +} + +/* Interface routine */ +static int +sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) +{ + struct sisusb_usb_data *sisusb; + u16 eattr = c->vc_video_erase_char; + ssize_t written; + int copyall = 0; + unsigned long oldorigin; + unsigned int delta = lines * c->vc_size_row; + u32 originoffset; + + /* Returning != 0 means we have done the scrolling successfully. + * Returning 0 makes vt do the scrolling on its own. + * Note that con_scroll is only called if the console is + * visible. In that case, the origin should be our buffer, + * not the vt's private one. + */ + + if (!lines) + return 1; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return 0; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb)) { + up(&sisusb->lock); + return 0; + } + + /* Special case */ + if (t || b != c->vc_rows) + return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines); + + if (c->vc_origin != c->vc_visible_origin) { + c->vc_visible_origin = c->vc_origin; + sisusbcon_set_start_address(sisusb, c); + } + + /* limit amount to maximum realistic size */ + if (lines > c->vc_rows) + lines = c->vc_rows; + + oldorigin = c->vc_origin; + + switch (dir) { + + case SM_UP: + + if (c->vc_scr_end + delta >= + sisusb->scrbuf + sisusb->scrbuf_size) { + sisusbcon_memcpyw((u16 *)sisusb->scrbuf, + (u16 *)(oldorigin + delta), + c->vc_screenbuf_size - delta); + c->vc_origin = sisusb->scrbuf; + sisusb->con_rolled_over = oldorigin - sisusb->scrbuf; + copyall = 1; + } else + c->vc_origin += delta; + + sisusbcon_memsetw( + (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), + eattr, delta); + + break; + + case SM_DOWN: + + if (oldorigin - delta < sisusb->scrbuf) { + sisusbcon_memmovew((u16 *)(sisusb->scrbuf + + sisusb->scrbuf_size - + c->vc_screenbuf_size + + delta), + (u16 *)oldorigin, + c->vc_screenbuf_size - delta); + c->vc_origin = sisusb->scrbuf + + sisusb->scrbuf_size - + c->vc_screenbuf_size; + sisusb->con_rolled_over = 0; + copyall = 1; + } else + c->vc_origin -= delta; + + c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; + + scr_memsetw((u16 *)(c->vc_origin), eattr, delta); + + break; + } + + originoffset = (u32)(c->vc_origin - sisusb->scrbuf); + + if (copyall) + sisusb_copy_memory(sisusb, + (char *)c->vc_origin, + (u32)(sisusb->vrambase + originoffset), + c->vc_screenbuf_size, &written); + else if (dir == SM_UP) + sisusb_copy_memory(sisusb, + (char *)c->vc_origin + c->vc_screenbuf_size - delta, + (u32)sisusb->vrambase + originoffset + + c->vc_screenbuf_size - delta, + delta, &written); + else + sisusb_copy_memory(sisusb, + (char *)c->vc_origin, + (u32)(sisusb->vrambase + originoffset), + delta, &written); + + c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; + c->vc_visible_origin = c->vc_origin; + + sisusbcon_set_start_address(sisusb, c); + + c->vc_pos = c->vc_pos - oldorigin + c->vc_origin; + + up(&sisusb->lock); + + return 1; +} + +/* Interface routine */ +static int +sisusbcon_set_origin(struct vc_data *c) +{ + struct sisusb_usb_data *sisusb; + + /* Returning != 0 means we were successful. + * Returning 0 will vt make to use its own + * screenbuffer as the origin. + */ + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return 0; + + /* sisusb->lock is down */ + + if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) { + up(&sisusb->lock); + return 0; + } + + c->vc_origin = c->vc_visible_origin = sisusb->scrbuf; + + sisusbcon_set_start_address(sisusb, c); + + sisusb->con_rolled_over = 0; + + up(&sisusb->lock); + + return 1; +} + +/* Interface routine */ +static int +sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) +{ + struct sisusb_usb_data *sisusb; + int fh; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return -ENODEV; + + fh = sisusb->current_font_height; + + up(&sisusb->lock); + + /* We are quite unflexible as regards resizing. The vt code + * handles sizes where the line length isn't equal the pitch + * quite badly. As regards the rows, our panning tricks only + * work well if the number of rows equals the visible number + * of rows. + */ + + if (newcols != 80 || c->vc_scan_lines / fh != newrows) + return -EINVAL; + + return 0; +} + +int +sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, + u8 *arg, int cmapsz, int ch512, int dorecalc, + struct vc_data *c, int fh, int uplock) +{ + int font_select = 0x00, i, err = 0; + u32 offset = 0; + u8 dummy; + + /* sisusb->lock is down */ + + /* + * The default font is kept in slot 0. + * A user font is loaded in slot 2 (256 ch) + * or 2+3 (512 ch). + */ + + if ((slot != 0 && slot != 2) || !fh) { + if (uplock) + up(&sisusb->lock); + return -EINVAL; + } + + if (set) + sisusb->font_slot = slot; + + /* Default font is always 256 */ + if (slot == 0) + ch512 = 0; + else + offset = 4 * cmapsz; + + font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a); + + err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ + err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */ + err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */ + err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */ + + if (err) + goto font_op_error; + + err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */ + err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */ + err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */ + + if (err) + goto font_op_error; + + if (arg) { + if (set) + for (i = 0; i < cmapsz; i++) { + err |= sisusb_writeb(sisusb, + sisusb->vrambase + offset + i, + arg[i]); + if (err) + break; + } + else + for (i = 0; i < cmapsz; i++) { + err |= sisusb_readb(sisusb, + sisusb->vrambase + offset + i, + &arg[i]); + if (err) + break; + } + + /* + * In 512-character mode, the character map is not contiguous if + * we want to remain EGA compatible -- which we do + */ + + if (ch512) { + if (set) + for (i = 0; i < cmapsz; i++) { + err |= sisusb_writeb(sisusb, + sisusb->vrambase + offset + + (2 * cmapsz) + i, + arg[cmapsz + i]); + if (err) + break; + } + else + for (i = 0; i < cmapsz; i++) { + err |= sisusb_readb(sisusb, + sisusb->vrambase + offset + + (2 * cmapsz) + i, + &arg[cmapsz + i]); + if (err) + break; + } + } + } + + if (err) + goto font_op_error; + + err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ + err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */ + err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */ + if (set) + sisusb_setidxreg(sisusb, SISSR, 0x03, font_select); + err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */ + + if (err) + goto font_op_error; + + err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */ + err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */ + err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */ + + if (err) + goto font_op_error; + + if ((set) && (ch512 != sisusb->current_font_512)) { + + /* Font is shared among all our consoles. + * And so is the hi_font_mask. + */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *c = vc_cons[i].d; + if (c && c->vc_sw == &sisusb_con) + c->vc_hi_font_mask = ch512 ? 0x0800 : 0; + } + + sisusb->current_font_512 = ch512; + + /* color plane enable register: + 256-char: enable intensity bit + 512-char: disable intensity bit */ + sisusb_getreg(sisusb, SISINPSTAT, &dummy); + sisusb_setreg(sisusb, SISAR, 0x12); + sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f); + + sisusb_getreg(sisusb, SISINPSTAT, &dummy); + sisusb_setreg(sisusb, SISAR, 0x20); + sisusb_getreg(sisusb, SISINPSTAT, &dummy); + } + + if (dorecalc) { + + /* + * Adjust the screen to fit a font of a certain height + */ + + unsigned char ovr, vde, fsr; + int rows = 0, maxscan = 0; + + if (c) { + + /* Number of video rows */ + rows = c->vc_scan_lines / fh; + /* Scan lines to actually display-1 */ + maxscan = rows * fh - 1; + + /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n", + rows, maxscan, fh, c->vc_scan_lines);*/ + + sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr); + vde = maxscan & 0xff; + ovr = (ovr & 0xbd) | + ((maxscan & 0x100) >> 7) | + ((maxscan & 0x200) >> 3); + sisusb_setidxreg(sisusb, SISCR, 0x07, ovr); + sisusb_setidxreg(sisusb, SISCR, 0x12, vde); + + } + + sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr); + fsr = (fsr & 0xe0) | (fh - 1); + sisusb_setidxreg(sisusb, SISCR, 0x09, fsr); + sisusb->current_font_height = fh; + + sisusb->sisusb_cursor_size_from = -1; + sisusb->sisusb_cursor_size_to = -1; + + } + + if (uplock) + up(&sisusb->lock); + + if (dorecalc && c) { + int i, rows = c->vc_scan_lines / fh; + + /* Now adjust our consoles' size */ + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *vc = vc_cons[i].d; + + if (vc && vc->vc_sw == &sisusb_con) { + if (CON_IS_VISIBLE(vc)) { + vc->vc_sw->con_cursor(vc, CM_DRAW); + } + vc->vc_font.height = fh; + vc_resize(vc, 0, rows); + } + } + } + + return 0; + +font_op_error: + if (uplock) + up(&sisusb->lock); + + return -EIO; +} + +/* Interface routine */ +static int +sisusbcon_font_set(struct vc_data *c, struct console_font *font, + unsigned flags) +{ + struct sisusb_usb_data *sisusb; + unsigned charcount = font->charcount; + + if (font->width != 8 || (charcount != 256 && charcount != 512)) + return -EINVAL; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return -ENODEV; + + /* sisusb->lock is down */ + + /* Save the user-provided font into a buffer. This + * is used for restoring text mode after quitting + * from X and for the con_getfont routine. + */ + if (sisusb->font_backup) { + if (sisusb->font_backup_size < charcount) { + vfree(sisusb->font_backup); + sisusb->font_backup = NULL; + } + } + + if (!sisusb->font_backup) + sisusb->font_backup = vmalloc(charcount * 32); + + if (sisusb->font_backup) { + memcpy(sisusb->font_backup, font->data, charcount * 32); + sisusb->font_backup_size = charcount; + sisusb->font_backup_height = font->height; + sisusb->font_backup_512 = (charcount == 512) ? 1 : 0; + } + + /* do_font_op ups sisusb->lock */ + + return sisusbcon_do_font_op(sisusb, 1, 2, font->data, + 8192, (charcount == 512), + (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0, + c, font->height, 1); +} + +/* Interface routine */ +static int +sisusbcon_font_get(struct vc_data *c, struct console_font *font) +{ + struct sisusb_usb_data *sisusb; + + if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) + return -ENODEV; + + /* sisusb->lock is down */ + + font->width = 8; + font->height = c->vc_font.height; + font->charcount = 256; + + if (!font->data) { + up(&sisusb->lock); + return 0; + } + + if (!sisusb->font_backup) { + up(&sisusb->lock); + return -ENODEV; + } + + /* Copy 256 chars only, like vgacon */ + memcpy(font->data, sisusb->font_backup, 256 * 32); + + up(&sisusb->lock); + + return 0; +} + +/* + * The console `switch' structure for the sisusb console + */ + +static const struct consw sisusb_con = { + .owner = THIS_MODULE, + .con_startup = sisusbcon_startup, + .con_init = sisusbcon_init, + .con_deinit = sisusbcon_deinit, + .con_clear = sisusbcon_clear, + .con_putc = sisusbcon_putc, + .con_putcs = sisusbcon_putcs, + .con_cursor = sisusbcon_cursor, + .con_scroll = sisusbcon_scroll, + .con_bmove = sisusbcon_bmove, + .con_switch = sisusbcon_switch, + .con_blank = sisusbcon_blank, + .con_font_set = sisusbcon_font_set, + .con_font_get = sisusbcon_font_get, + .con_set_palette = sisusbcon_set_palette, + .con_scrolldelta = sisusbcon_scrolldelta, + .con_build_attr = sisusbcon_build_attr, + .con_invert_region = sisusbcon_invert_region, + .con_set_origin = sisusbcon_set_origin, + .con_save_screen = sisusbcon_save_screen, + .con_resize = sisusbcon_resize, +}; + +/* Our very own dummy console driver */ + +static const char *sisusbdummycon_startup(void) +{ + return "SISUSBVGADUMMY"; +} + +static void sisusbdummycon_init(struct vc_data *vc, int init) +{ + vc->vc_can_do_color = 1; + if (init) { + vc->vc_cols = 80; + vc->vc_rows = 25; + } else + vc_resize(vc, 80, 25); +} + +static int sisusbdummycon_dummy(void) +{ + return 0; +} + +#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy + +const struct consw sisusb_dummy_con = { + .owner = THIS_MODULE, + .con_startup = sisusbdummycon_startup, + .con_init = sisusbdummycon_init, + .con_deinit = SISUSBCONDUMMY, + .con_clear = SISUSBCONDUMMY, + .con_putc = SISUSBCONDUMMY, + .con_putcs = SISUSBCONDUMMY, + .con_cursor = SISUSBCONDUMMY, + .con_scroll = SISUSBCONDUMMY, + .con_bmove = SISUSBCONDUMMY, + .con_switch = SISUSBCONDUMMY, + .con_blank = SISUSBCONDUMMY, + .con_font_set = SISUSBCONDUMMY, + .con_font_get = SISUSBCONDUMMY, + .con_font_default = SISUSBCONDUMMY, + .con_font_copy = SISUSBCONDUMMY, + .con_set_palette = SISUSBCONDUMMY, + .con_scrolldelta = SISUSBCONDUMMY, +}; + +int +sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) +{ + int i, ret, minor = sisusb->minor; + + down(&disconnect_sem); + + down(&sisusb->lock); + + /* Erm.. that should not happen */ + if (sisusb->haveconsole || !sisusb->SiS_Pr) { + up(&sisusb->lock); + up(&disconnect_sem); + return 1; + } + + sisusb->con_first = first; + sisusb->con_last = last; + + if (first > last || + first > MAX_NR_CONSOLES || + last > MAX_NR_CONSOLES) { + up(&sisusb->lock); + up(&disconnect_sem); + return 1; + } + + /* If gfxcore not initialized or no consoles given, quit graciously */ + if (!sisusb->gfxinit || first < 1 || last < 1) { + up(&sisusb->lock); + up(&disconnect_sem); + return 0; + } + + sisusb->sisusb_cursor_loc = -1; + sisusb->sisusb_cursor_size_from = -1; + sisusb->sisusb_cursor_size_to = -1; + + /* Set up text mode (and upload default font) */ + if (sisusb_reset_text_mode(sisusb, 1)) { + up(&sisusb->lock); + up(&disconnect_sem); + printk(KERN_ERR + "sisusbvga[%d]: Failed to set up text mode\n", + minor); + return 1; + } + + /* Initialize some gfx registers */ + sisusb_initialize(sisusb); + + for (i = first - 1; i <= last - 1; i++) { + /* Save sisusb for our interface routines */ + mysisusbs[i] = sisusb; + } + + /* Initial console setup */ + sisusb->sisusb_num_columns = 80; + + /* Use a 32K buffer (matches b8000-bffff area) */ + sisusb->scrbuf_size = 32 * 1024; + + /* Allocate screen buffer */ + if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { + up(&sisusb->lock); + up(&disconnect_sem); + printk(KERN_ERR + "sisusbvga[%d]: Failed to allocate screen buffer\n", + minor); + return 1; + } + + up(&sisusb->lock); + up(&disconnect_sem); + + /* Now grab the desired console(s) */ + ret = take_over_console(&sisusb_con, first - 1, last - 1, 0); + + if (!ret) + sisusb->haveconsole = 1; + else { + for (i = first - 1; i <= last - 1; i++) + mysisusbs[i] = NULL; + } + + return ret; +} + +void +sisusb_console_exit(struct sisusb_usb_data *sisusb) +{ + int i; + + /* This is called if the device is disconnected + * and while disconnect and lock semaphores + * are up. This should be save because we + * can't lose our sisusb any other way but by + * disconnection (and hence, the disconnect + * sema is for protecting all other access + * functions from disconnection, not the + * other way round). + */ + + /* Now what do we do in case of disconnection: + * One alternative would be to simply call + * give_up_console(). Nah, not a good idea. + * give_up_console() is obviously buggy as it + * only discards the consw pointer from the + * driver_map, but doesn't adapt vc->vc_sw + * of the affected consoles. Hence, the next + * call to any of the console functions will + * eventually take a trip to oops county. + * Also, give_up_console for some reason + * doesn't decrement our module refcount. + * Instead, we switch our consoles to a private + * dummy console. This, of course, keeps our + * refcount up as well, but it works perfectly. + */ + + if (sisusb->haveconsole) { + for (i = 0; i < MAX_NR_CONSOLES; i++) + if (sisusb->havethisconsole[i]) + take_over_console(&sisusb_dummy_con, i, i, 0); + /* At this point, con_deinit for all our + * consoles is executed by take_over_console(). + */ + sisusb->haveconsole = 0; + } + + vfree((void *)sisusb->scrbuf); + sisusb->scrbuf = 0; + + vfree(sisusb->font_backup); + sisusb->font_backup = NULL; +} + +void __init sisusb_init_concode(void) +{ + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) + mysisusbs[i] = NULL; +} + +#endif /* INCL_CON */ + + + diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c new file mode 100644 index 00000000000..f28bc240f9b --- /dev/null +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -0,0 +1,1047 @@ +/* + * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles + * + * Display mode initializing code + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, this code is licensed under the + * terms of the GPL v2. + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/kref.h> + +#include "sisusb.h" + +#ifdef INCL_SISUSB_CON + +#include "sisusb_init.h" + +/*********************************************/ +/* POINTER INITIALIZATION */ +/*********************************************/ + +static void +SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; + + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; + + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; +} + +/*********************************************/ +/* HELPER: Get ModeID */ +/*********************************************/ + +unsigned short +SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) +{ + unsigned short ModeIndex = 0; + + switch (HDisplay) + { + case 320: + if (VDisplay == 200) + ModeIndex = ModeIndex_320x200[Depth]; + else if (VDisplay == 240) + ModeIndex = ModeIndex_320x240[Depth]; + break; + case 400: + if (VDisplay == 300) + ModeIndex = ModeIndex_400x300[Depth]; + break; + case 512: + if (VDisplay == 384) + ModeIndex = ModeIndex_512x384[Depth]; + break; + case 640: + if (VDisplay == 480) + ModeIndex = ModeIndex_640x480[Depth]; + else if (VDisplay == 400) + ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if (VDisplay == 480) + ModeIndex = ModeIndex_720x480[Depth]; + else if (VDisplay == 576) + ModeIndex = ModeIndex_720x576[Depth]; + break; + case 768: + if (VDisplay == 576) + ModeIndex = ModeIndex_768x576[Depth]; + break; + case 800: + if (VDisplay == 600) + ModeIndex = ModeIndex_800x600[Depth]; + else if (VDisplay == 480) + ModeIndex = ModeIndex_800x480[Depth]; + break; + case 848: + if (VDisplay == 480) + ModeIndex = ModeIndex_848x480[Depth]; + break; + case 856: + if (VDisplay == 480) + ModeIndex = ModeIndex_856x480[Depth]; + break; + case 960: + if (VDisplay == 540) + ModeIndex = ModeIndex_960x540[Depth]; + else if (VDisplay == 600) + ModeIndex = ModeIndex_960x600[Depth]; + break; + case 1024: + if (VDisplay == 576) + ModeIndex = ModeIndex_1024x576[Depth]; + else if (VDisplay == 768) + ModeIndex = ModeIndex_1024x768[Depth]; + break; + case 1152: + if (VDisplay == 864) + ModeIndex = ModeIndex_1152x864[Depth]; + break; + case 1280: + switch (VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + break; + case 768: + ModeIndex = ModeIndex_1280x768[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + } + + return ModeIndex; +} + +/*********************************************/ +/* HELPER: SetReg, GetReg */ +/*********************************************/ + +static void +SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short data) +{ + sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); +} + +static void +SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short data) +{ + sisusb_setreg(SiS_Pr->sisusb, port, data); +} + +static unsigned char +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index) +{ + u8 data; + + sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data); + + return data; +} + +static unsigned char +SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) +{ + u8 data; + + sisusb_getreg(SiS_Pr->sisusb, port, &data); + + return data; +} + +static void +SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataAND, + unsigned short DataOR) +{ + sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); +} + +static void +SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataAND) +{ + sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); +} + +static void +SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, + unsigned short index, unsigned short DataOR) +{ + sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); +} + +/*********************************************/ +/* HELPER: DisplayOn, DisplayOff */ +/*********************************************/ + +static void +SiS_DisplayOn(struct SiS_Private *SiS_Pr) +{ + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); +} + +/*********************************************/ +/* HELPER: Init Port Addresses */ +/*********************************************/ + +void +SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +{ + SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; + SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; + SiS_Pr->SiS_P3c0 = BaseAddr + 0x10; + SiS_Pr->SiS_P3ce = BaseAddr + 0x1e; + SiS_Pr->SiS_P3c2 = BaseAddr + 0x12; + SiS_Pr->SiS_P3ca = BaseAddr + 0x1a; + SiS_Pr->SiS_P3c6 = BaseAddr + 0x16; + SiS_Pr->SiS_P3c7 = BaseAddr + 0x17; + SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; + SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; + SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; + SiS_Pr->SiS_P3cc = BaseAddr + 0x1c; + SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; + SiS_Pr->SiS_P3da = BaseAddr + 0x2a; + SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; +} + +/*********************************************/ +/* HELPER: GetSysFlags */ +/*********************************************/ + +static void +SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_MyCR63 = 0x63; +} + +/*********************************************/ +/* HELPER: Init PCI & Engines */ +/*********************************************/ + +static void +SiSInitPCIetc(struct SiS_Private *SiS_Pr) +{ + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); + /* - Enable 2D (0x40) + * - Enable 3D (0x02) + * - Enable 3D vertex command fetch (0x10) + * - Enable 3D command parser (0x08) + * - Enable 3D G/L transformation engine (0x80) + */ + SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA); +} + +/*********************************************/ +/* HELPER: SET SEGMENT REGISTERS */ +/*********************************************/ + +static void +SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0; + temp |= (value >> 4); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0; + temp |= (value & 0x0f); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp; + + value &= 0x00ff; + temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f; + temp |= (value & 0xf0); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); + temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f; + temp |= (value << 4); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); +} + +static void +SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +{ + SiS_SetSegRegLower(SiS_Pr, value); + SiS_SetSegRegUpper(SiS_Pr, value); +} + +static void +SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +{ + SiS_SetSegmentReg(SiS_Pr, 0); +} + +static void +SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) +{ + unsigned short temp = value >> 8; + + temp &= 0x07; + temp |= (temp << 4); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp); + SiS_SetSegmentReg(SiS_Pr, value); +} + +static void +SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +{ + SiS_SetSegmentRegOver(SiS_Pr, 0); +} + +static void +SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +{ + SiS_ResetSegmentReg(SiS_Pr); + SiS_ResetSegmentRegOver(SiS_Pr); +} + +/*********************************************/ +/* HELPER: SearchModeID */ +/*********************************************/ + +static int +SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex) +{ + if ((*ModeNo) <= 0x13) { + + if ((*ModeNo) != 0x03) + return 0; + + (*ModeIdIndex) = 0; + + } else { + + for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + break; + + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + return 0; + } + + } + + return 1; +} + +/*********************************************/ +/* HELPER: ENABLE CRT1 */ +/*********************************************/ + +static void +SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +{ + /* Enable CRT1 gating */ + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); +} + +/*********************************************/ +/* HELPER: GetColorDepth */ +/*********************************************/ + +static unsigned short +SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + unsigned short modeflag; + short index; + + if (ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + index = (modeflag & ModeTypeMask) - ModeEGA; + if (index < 0) index = 0; + return ColorDepth[index]; +} + +/*********************************************/ +/* HELPER: GetOffset */ +/*********************************************/ + +static unsigned short +SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short rrti) +{ + unsigned short xres, temp, colordepth, infoflag; + + infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + xres = SiS_Pr->SiS_RefIndex[rrti].XRes; + + colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex); + + temp = xres / 16; + + if (infoflag & InterlaceMode) + temp <<= 1; + + temp *= colordepth; + + if (xres % 16) + temp += (colordepth >> 1); + + return temp; +} + +/*********************************************/ +/* SEQ */ +/*********************************************/ + +static void +SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char SRdata; + int i; + + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03); + + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); + + for(i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); + } +} + +/*********************************************/ +/* MISC */ +/*********************************************/ + +static void +SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; + + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata); +} + +/*********************************************/ +/* CRTC */ +/*********************************************/ + +static void +SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char CRTCdata; + unsigned short i; + + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); + + for(i = 0; i <= 0x18; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); + } +} + +/*********************************************/ +/* ATT */ +/*********************************************/ + +static void +SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char ARdata; + unsigned short i; + + for(i = 0; i <= 0x13; i++) { + ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; + SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata); + } + SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00); + + SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20); + SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); +} + +/*********************************************/ +/* GRC */ +/*********************************************/ + +static void +SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) +{ + unsigned char GRdata; + unsigned short i; + + for(i = 0; i <= 0x08; i++) { + GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); + } + + if (SiS_Pr->SiS_ModeType > ModeVGA) { + /* 256 color disable */ + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF); + } +} + +/*********************************************/ +/* CLEAR EXTENDED REGISTERS */ +/*********************************************/ + +static void +SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + int i; + + for(i = 0x0A; i <= 0x0E; i++) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); + } + + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE); +} + +/*********************************************/ +/* Get rate index */ +/*********************************************/ + +static unsigned short +SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + unsigned short rrti, i, index, temp; + + if (ModeNo <= 0x13) + return 0xFFFF; + + index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) index--; + + rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; + + i = 0; + do { + if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) + break; + + temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + if (temp < SiS_Pr->SiS_ModeType) + break; + + i++; + index--; + } while(index != 0xFFFF); + + i--; + + return (rrti + i); +} + +/*********************************************/ +/* SYNC */ +/*********************************************/ + +static void +SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +{ + unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; + sync &= 0xC0; + sync |= 0x2f; + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync); +} + +/*********************************************/ +/* CRTC/2 */ +/*********************************************/ + +static void +SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short rrti) +{ + unsigned char index; + unsigned short temp, i, j, modeflag; + + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; + + for(i = 0,j = 0; i <= 7; i++, j++) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, + SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j = 0x10; i <= 10; i++, j++) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, + SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j = 0x15; i <= 12; i++, j++) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, + SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j = 0x0A; i <= 15; i++, j++) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, + SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + + temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; + SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + + temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; + if (modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); + + if (SiS_Pr->SiS_ModeType > ModeVGA) + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F); +} + +/*********************************************/ +/* OFFSET & PITCH */ +/*********************************************/ +/* (partly overruled by SetPitch() in XF86) */ +/*********************************************/ + +static void +SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short rrti) +{ + unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short temp; + + temp = (du >> 8) & 0x0f; + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp); + + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); + + if (infoflag & InterlaceMode) du >>= 1; + + du <<= 5; + temp = (du >> 8) & 0xff; + if (du & 0xff) temp++; + temp++; + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); +} + +/*********************************************/ +/* VCLK */ +/*********************************************/ + +static void +SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short rrti) +{ + unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; + unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; + unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; + + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + + SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); + SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); + SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); +} + +/*********************************************/ +/* FIFO */ +/*********************************************/ + +static void +SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) +{ + unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; + + /* disable auto-threshold */ + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE); + + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0); + + if (ModeNo <= 0x13) + return; + + if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34); + SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01); + } +} + +/*********************************************/ +/* MODE REGISTERS */ +/*********************************************/ + +static void +SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short rrti) +{ + unsigned short data = 0, VCLK = 0, index = 0; + + if (ModeNo > 0x13) { + index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + + if (VCLK >= 166) data |= 0x0c; + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); + + if (VCLK >= 166) + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7); + + /* DAC speed */ + data = 0x03; + if (VCLK >= 260) + data = 0x00; + else if (VCLK >= 160) + data = 0x01; + else if (VCLK >= 135) + data = 0x02; + + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data); +} + +static void +SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short rrti) +{ + unsigned short data, infoflag = 0, modeflag; + + if (ModeNo <= 0x13) + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + } + + /* Disable DPMS */ + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F); + + data = 0; + if (ModeNo > 0x13) { + if (SiS_Pr->SiS_ModeType > ModeEGA) { + data |= 0x02; + data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); + } + if (infoflag & InterlaceMode) data |= 0x20; + } + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); + + data = 0; + if (infoflag & InterlaceMode) { + /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ + unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; + unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + data = hrs - (hto >> 1) + 3; + } + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8)); + + if (modeflag & HalfDCLK) + SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08); + + data = 0; + if (modeflag & LineCompareOff) + data = 0x08; + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data); + + if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13)) + SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40); + + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb); + + data = 0x60; + if (SiS_Pr->SiS_ModeType != ModeText) { + data ^= 0x60; + if (SiS_Pr->SiS_ModeType != ModeEGA) + data ^= 0xA0; + } + SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data); + + SiS_SetVCLKState(SiS_Pr, ModeNo, rrti); + + if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40) + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c); + else + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c); +} + +/*********************************************/ +/* LOAD DAC */ +/*********************************************/ + +static void +SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) +{ + unsigned short d1, d2, d3; + + switch (dl) { + case 0: + d1 = dh; d2 = ah; d3 = al; + break; + case 1: + d1 = ah; d2 = al; d3 = dh; + break; + default: + d1 = al; d2 = dh; d3 = ah; + } + SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); + SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); + SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag)); +} + +static void +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +{ + unsigned short data, data2, time, i, j, k, m, n, o; + unsigned short si, di, bx, sf; + unsigned long DACAddr, DACData; + const unsigned char *table = NULL; + + if (ModeNo < 0x13) + data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag; + else + data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; + + data &= DACInfoFlag; + + j = time = 64; + if (data == 0x00) + table = SiS_MDA_DAC; + else if (data == 0x08) + table = SiS_CGA_DAC; + else if (data == 0x10) + table = SiS_EGA_DAC; + else { + j = 16; + time = 256; + table = SiS_VGA_DAC; + } + + DACAddr = SiS_Pr->SiS_P3c8; + DACData = SiS_Pr->SiS_P3c9; + sf = 0; + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); + + SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); + + for(i = 0; i < j; i++) { + data = table[i]; + for(k = 0; k < 3; k++) { + data2 = 0; + if (data & 0x01) data2 += 0x2A; + if (data & 0x02) data2 += 0x15; + SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); + data >>= 2; + } + } + + if (time == 256) { + for(i = 16; i < 32; i++) { + data = table[i] << sf; + for(k = 0; k < 3; k++) + SiS_SetRegByte(SiS_Pr, DACData, data); + } + si = 32; + for(m = 0; m < 9; m++) { + di = si; + bx = si + 4; + for(n = 0; n < 3; n++) { + for(o = 0; o < 5; o++) { + SiS_WriteDAC(SiS_Pr, DACData, sf, n, + table[di], table[bx], table[si]); + si++; + } + si -= 2; + for(o = 0; o < 3; o++) { + SiS_WriteDAC(SiS_Pr, DACData, sf, n, + table[di], table[si], table[bx]); + si--; + } + } + si += 5; + } + } +} + +/*********************************************/ +/* SET CRT1 REGISTER GROUP */ +/*********************************************/ + +static void +SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + unsigned short StandTableIndex, rrti; + + SiS_Pr->SiS_CRT1Mode = ModeNo; + + if (ModeNo <= 0x13) + StandTableIndex = 0; + else + StandTableIndex = 1; + + SiS_ResetSegmentRegisters(SiS_Pr); + SiS_SetSeqRegs(SiS_Pr, StandTableIndex); + SiS_SetMiscRegs(SiS_Pr, StandTableIndex); + SiS_SetCRTCRegs(SiS_Pr, StandTableIndex); + SiS_SetATTRegs(SiS_Pr, StandTableIndex); + SiS_SetGRCRegs(SiS_Pr, StandTableIndex); + SiS_ClearExt1Regs(SiS_Pr, ModeNo); + + rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); + + if (rrti != 0xFFFF) { + SiS_SetCRT1Sync(SiS_Pr, rrti); + SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti); + SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti); + SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti); + } + + SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti); + + SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_DisplayOn(SiS_Pr); +} + +/*********************************************/ +/* SiSSetMode() */ +/*********************************************/ + +int +SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +{ + unsigned short ModeIdIndex; + unsigned long BaseAddr = SiS_Pr->IOAddress; + + SiSUSB_InitPtr(SiS_Pr); + SiSUSBRegInit(SiS_Pr, BaseAddr); + SiS_GetSysFlags(SiS_Pr); + + if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) + return 0; + + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86); + + SiSInitPCIetc(SiS_Pr); + + ModeNo &= 0x7f; + + SiS_Pr->SiS_ModeType = + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + + SiS_Pr->SiS_SetFlag = LowModeTests; + + /* Set mode on CRT1 */ + SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_HandleCRT1(SiS_Pr); + + SiS_DisplayOn(SiS_Pr); + SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); + + /* Store mode number */ + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo); + + return 1; +} + +int +SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +{ + unsigned short ModeNo = 0; + int i; + + SiSUSB_InitPtr(SiS_Pr); + + if (VModeNo == 0x03) { + + ModeNo = 0x03; + + } else { + + i = 0; + do { + + if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) { + ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID; + break; + } + + } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff); + + } + + if (!ModeNo) + return 0; + + return SiSUSBSetMode(SiS_Pr, ModeNo); +} + +#endif /* INCL_SISUSB_CON */ + + + + diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h new file mode 100644 index 00000000000..5b11577835c --- /dev/null +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -0,0 +1,830 @@ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data and prototypes for init.c + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * 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 named License, + * * or 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 + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _SISUSB_INIT_H_ +#define _SISUSB_INIT_H_ + +/* SiS_ModeType */ +#define ModeText 0x00 +#define ModeCGA 0x01 +#define ModeEGA 0x02 +#define ModeVGA 0x03 +#define Mode15Bpp 0x04 +#define Mode16Bpp 0x05 +#define Mode24Bpp 0x06 +#define Mode32Bpp 0x07 + +#define ModeTypeMask 0x07 +#define IsTextMode 0x07 + +#define DACInfoFlag 0x0018 +#define MemoryInfoFlag 0x01E0 +#define MemorySizeShift 5 + +/* modeflag */ +#define Charx8Dot 0x0200 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define DoubleScanMode 0x8000 + +/* Infoflag */ +#define SupportTV 0x0008 +#define SupportTV1024 0x0800 +#define SupportCHTV 0x0800 +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define SupportHiVision 0x0010 +#define SupportYPbPr750p 0x1000 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xc000 + +/* SetFlag */ +#define ProgrammingCRT2 0x0001 +#define LowModeTests 0x0002 +#define LCDVESATiming 0x0008 +#define EnableLVDSDDA 0x0010 +#define SetDispDevSwitchFlag 0x0020 +#define CheckWinDos 0x0040 +#define SetDOSMode 0x0080 + +/* Index in ModeResInfo table */ +#define SIS_RI_320x200 0 +#define SIS_RI_320x240 1 +#define SIS_RI_320x400 2 +#define SIS_RI_400x300 3 +#define SIS_RI_512x384 4 +#define SIS_RI_640x400 5 +#define SIS_RI_640x480 6 +#define SIS_RI_800x600 7 +#define SIS_RI_1024x768 8 +#define SIS_RI_1280x1024 9 +#define SIS_RI_1600x1200 10 +#define SIS_RI_1920x1440 11 +#define SIS_RI_2048x1536 12 +#define SIS_RI_720x480 13 +#define SIS_RI_720x576 14 +#define SIS_RI_1280x960 15 +#define SIS_RI_800x480 16 +#define SIS_RI_1024x576 17 +#define SIS_RI_1280x720 18 +#define SIS_RI_856x480 19 +#define SIS_RI_1280x768 20 +#define SIS_RI_1400x1050 21 +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_848x480 23 +#define SIS_RI_1360x768 24 +#define SIS_RI_1024x600 25 +#define SIS_RI_1152x768 26 +#define SIS_RI_768x576 27 +#define SIS_RI_1360x1024 28 +#define SIS_RI_1680x1050 29 +#define SIS_RI_1280x800 30 +#define SIS_RI_1920x1080 31 +#define SIS_RI_960x540 32 +#define SIS_RI_960x600 33 + +#define SIS_VIDEO_CAPTURE 0x00 - 0x30 +#define SIS_VIDEO_PLAYBACK 0x02 - 0x30 +#define SIS_CRT2_PORT_04 0x04 - 0x30 + +/* Mode numbers */ +static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; +static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; +static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; +static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; +static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; +static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; +static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; +static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; +static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; +static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; +static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; +static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; +static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; +static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; +static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; +static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; +static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; +static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; +static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; +static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; +static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; + +static const unsigned char SiS_MDA_DAC[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +}; + +static const unsigned char SiS_CGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const unsigned char SiS_EGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, + 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, + 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, + 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, + 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, + 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, + 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +}; + +static const unsigned char SiS_VGA_DAC[] = +{ + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, + 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, + 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, + 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, + 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, + 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, + 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, + 0x0B,0x0C,0x0D,0x0F,0x10 +}; + +static const struct SiS_St SiSUSB_SModeIDTable[] = +{ + {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, + {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = +{ + { 640,400}, + { 640,350}, + { 720,400}, + { 720,350}, + { 640,480} +}; + +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = +{ + { 320, 200, 8, 8}, /* 0x00 */ + { 320, 240, 8, 8}, /* 0x01 */ + { 320, 400, 8, 8}, /* 0x02 */ + { 400, 300, 8, 8}, /* 0x03 */ + { 512, 384, 8, 8}, /* 0x04 */ + { 640, 400, 8,16}, /* 0x05 */ + { 640, 480, 8,16}, /* 0x06 */ + { 800, 600, 8,16}, /* 0x07 */ + { 1024, 768, 8,16}, /* 0x08 */ + { 1280,1024, 8,16}, /* 0x09 */ + { 1600,1200, 8,16}, /* 0x0a */ + { 1920,1440, 8,16}, /* 0x0b */ + { 2048,1536, 8,16}, /* 0x0c */ + { 720, 480, 8,16}, /* 0x0d */ + { 720, 576, 8,16}, /* 0x0e */ + { 1280, 960, 8,16}, /* 0x0f */ + { 800, 480, 8,16}, /* 0x10 */ + { 1024, 576, 8,16}, /* 0x11 */ + { 1280, 720, 8,16}, /* 0x12 */ + { 856, 480, 8,16}, /* 0x13 */ + { 1280, 768, 8,16}, /* 0x14 */ + { 1400,1050, 8,16}, /* 0x15 */ + { 1152, 864, 8,16}, /* 0x16 */ + { 848, 480, 8,16}, /* 0x17 */ + { 1360, 768, 8,16}, /* 0x18 */ + { 1024, 600, 8,16}, /* 0x19 */ + { 1152, 768, 8,16}, /* 0x1a */ + { 768, 576, 8,16}, /* 0x1b */ + { 1360,1024, 8,16}, /* 0x1c */ + { 1680,1050, 8,16}, /* 0x1d */ + { 1280, 800, 8,16}, /* 0x1e */ + { 1920,1080, 8,16}, /* 0x1f */ + { 960, 540, 8,16}, /* 0x20 */ + { 960, 600, 8,16} /* 0x21 */ +}; + +static const struct SiS_StandTable SiSUSB_StandTable[] = +{ + /* MD_3_400 - mode 0x03 - 400 */ + { + 0x50,0x18,0x10,0x1000, + { 0x00,0x03,0x00,0x02 }, + 0x67, + { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff }, + { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08 }, + { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } + }, + /* Generic for VGA and higher */ + { + 0x00,0x00,0x00,0x0000, + { 0x01,0x0f,0x00,0x0e }, + 0x23, + { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, + 0xff }, + { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x01,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } + } +}; + +static const struct SiS_Ext SiSUSB_EModeIDTable[] = +{ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ + {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ + {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ + {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ + {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ + {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ + {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ + {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ + {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ + {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ + {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ + {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ + {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ + {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ + {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ + {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ + {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ + {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ + {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ + {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ + {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ + {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ + {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ + {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ + {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ + {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ + {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ + {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ + {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ + {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, + {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ + {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ + {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, + {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, + {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ + {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, + {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, + {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ + {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, + {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, + {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +}; + +static const struct SiS_Ext2 SiSUSB_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +}; + +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = +{ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, /* 0x0 */ + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, /* 0x1 */ + {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, + 0x01}}, /* 0x2 */ + {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, + 0x01}}, /* 0x3 */ + {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, /* 0x4 */ + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, /* 0x5 */ + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, + 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, + 0x00}}, /* 0x6 */ + {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, + 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, + 0x00}}, /* 0x7 */ + {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x00}}, /* 0x8 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, + 0x61}}, /* 0x9 */ + {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, + 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, + 0x61}}, /* 0xa */ + {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, + 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, + 0x61}}, /* 0xb */ + {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, + 0x00}}, /* 0xc */ + {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, + 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, + 0x01}}, /* 0xd */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, + 0x01}}, /* 0xe */ + {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, + 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, + 0x01}}, /* 0xf */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, + 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, + 0x01}}, /* 0x10 */ + {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, + 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, + 0x01}}, /* 0x11 */ + {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, + 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, + 0x61}}, /* 0x12 */ + {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, + 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, + 0x61}}, /* 0x13 */ + {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, + 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, + 0x61}}, /* 0x14 */ + {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, + 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, + 0x00}}, /* 0x15 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x16 */ + {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x17 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, + 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, + 0x01}}, /* 0x18 */ + {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, + 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, + 0x01}}, /* 0x19 */ + {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, + 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, + 0x62}}, /* 0x1a */ + {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, + 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, + 0x62}}, /* 0x1b */ + {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, + 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, + 0x00}}, /* 0x1c */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1d */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, + 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, + 0x01}}, /* 0x1e */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, + 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, + 0x01}}, /* 0x1f */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x20 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x21 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x22 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x23 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x24 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x25 */ + {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, + 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, + 0x00}}, /* 0x26 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x27 */ + {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, + 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, + 0x63}}, /* 0x28 */ + {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, + 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, + 0x63}}, /* 0x29 */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2a */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2b */ + {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, + 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, + 0x00}}, /* 0x2c */ + {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, + 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, + 0x44}}, /* 0x2d */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, + 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, + 0x44}}, /* 0x2e */ + {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, + 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, + 0x44}}, /* 0x2f */ + {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, + 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, + 0x44}}, /* 0x30 */ + {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, + 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, + 0x00}}, /* 0x31 */ + {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, + 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, + 0x01}}, /* 0x32 */ + {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, + 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, + 0x01}}, /* 0x33 */ + {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, + 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, + 0x01}}, /* 0x34 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, + 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, + 0x01}}, /* 0x35 */ + {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, + 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x36 */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, + 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, + 0x01}}, /* 0x37 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x38 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, + 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x39 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, + 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x3a */ + {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, + 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, + 0x01}}, /* 0x3b */ + {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, /* 0x3c */ + {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x3d */ + {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, + 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, + 0x00}}, /* 0x3e */ + {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, + 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x3f */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, + 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, + 0x01}}, /* 0x40 */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, + 0x01}}, /* 0x41 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, + 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, + 0x01}}, /* 0x42 */ + {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, + 0x00}}, /* 0x43 */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, + 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, + 0x01}}, /* 0x44 */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x45 */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, + 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, + 0x00}}, /* 0x46 */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, + 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, + 0x00}}, /* 0x47 */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, + 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, + 0x00}}, /* 0x48 */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, + 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, + 0x01}}, /* 0x49 */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, + 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, + 0x01}}, /* 0x4a */ + {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, + 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, + 0x00}}, /* 0x4b */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, + 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, + 0x01}}, /* 0x4c */ + {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, + {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, /* 0x4e */ + {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, + 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, + 0x21}}, /* 0x4f */ + {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, + 0x20}}, /* 0x50 */ + {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, + 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, + 0x61}}, /* 0x51 */ + {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, + 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, + 0x41}}, /* 0x52 */ + {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, + 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, + 0x01}}, /* 0x53 */ + {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, + 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, + 0x41}} /* 0x54 */ +}; + +static struct SiS_VCLKData SiSUSB_VCLKData[] = +{ + { 0x1b,0xe1, 25}, /* 0x00 */ + { 0x4e,0xe4, 28}, /* 0x01 */ + { 0x57,0xe4, 31}, /* 0x02 */ + { 0xc3,0xc8, 36}, /* 0x03 */ + { 0x42,0xe2, 40}, /* 0x04 */ + { 0xfe,0xcd, 43}, /* 0x05 */ + { 0x5d,0xc4, 44}, /* 0x06 */ + { 0x52,0xe2, 49}, /* 0x07 */ + { 0x53,0xe2, 50}, /* 0x08 */ + { 0x74,0x67, 52}, /* 0x09 */ + { 0x6d,0x66, 56}, /* 0x0a */ + { 0x5a,0x64, 65}, /* 0x0b */ + { 0x46,0x44, 67}, /* 0x0c */ + { 0xb1,0x46, 68}, /* 0x0d */ + { 0xd3,0x4a, 72}, /* 0x0e */ + { 0x29,0x61, 75}, /* 0x0f */ + { 0x6e,0x46, 76}, /* 0x10 */ + { 0x2b,0x61, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x41,104}, /* 0x17 */ + { 0x3a,0x23,105}, /* 0x18 */ + { 0x70,0x44,108}, /* 0x19 */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0x54,0x42,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x62,0x06,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x60,0x36, 30}, /* 0x41 Chrontel */ + { 0x40,0x4a, 28}, /* 0x42 Chrontel */ + { 0x9f,0x46, 44}, /* 0x43 Chrontel */ + { 0x97,0x2c, 26}, /* 0x44 */ + { 0x44,0xe4, 25}, /* 0x45 Chrontel */ + { 0x7e,0x32, 47}, /* 0x46 Chrontel */ + { 0x8a,0x24, 31}, /* 0x47 Chrontel */ + { 0x97,0x2c, 26}, /* 0x48 Chrontel */ + { 0xce,0x3c, 39}, /* 0x49 */ + { 0x52,0x4a, 36}, /* 0x4a Chrontel */ + { 0x34,0x61, 95}, /* 0x4b */ + { 0x78,0x27,108}, /* 0x4c - was 102 */ + { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + { 0x41,0x4e, 21}, /* 0x4e */ + { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ + { 0x19,0x42, 42}, /* 0x50 */ + { 0x54,0x46, 58}, /* 0x51 Chrontel */ + { 0x25,0x42, 61}, /* 0x52 */ + { 0x44,0x44, 66}, /* 0x53 Chrontel */ + { 0x3a,0x62, 70}, /* 0x54 Chrontel */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x45,0x25, 83}, /* 0x5c 1280x800 */ + { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 */ + { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ + { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ + { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ + { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ + { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ + { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ + { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ + { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ + { 0x45,0x25, 83}, /* 0x6c 1280x800 */ + { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ + { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +}; + +void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr); +unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); + +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 *data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); + +#endif + diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h new file mode 100644 index 00000000000..94edd4726c4 --- /dev/null +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -0,0 +1,169 @@ +/* + * General structure definitions for universal mode switching modules + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * 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 named License, + * * or 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 + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _SISUSB_STRUCT_H_ +#define _SISUSB_STRUCT_H_ + +struct SiS_St { + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; +}; + +struct SiS_StandTable +{ + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; +}; + +struct SiS_StResInfo_S { + unsigned short HTotal; + unsigned short VTotal; +}; + +struct SiS_Ext +{ + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; +}; + +struct SiS_Ext2 +{ + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; +}; + +struct SiS_CRT1Table +{ + unsigned char CR[17]; +}; + +struct SiS_VCLKData +{ + unsigned char SR2B,SR2C; + unsigned short CLOCK; +}; + +struct SiS_ModeResInfo +{ + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; +}; + +struct SiS_Private +{ + void *sisusb; + + unsigned long IOAddress; + + unsigned long SiS_P3c4; + unsigned long SiS_P3d4; + unsigned long SiS_P3c0; + unsigned long SiS_P3ce; + unsigned long SiS_P3c2; + unsigned long SiS_P3ca; + unsigned long SiS_P3c6; + unsigned long SiS_P3c7; + unsigned long SiS_P3c8; + unsigned long SiS_P3c9; + unsigned long SiS_P3cb; + unsigned long SiS_P3cc; + unsigned long SiS_P3cd; + unsigned long SiS_P3da; + unsigned long SiS_Part1Port; + + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; + + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; +}; + +#endif + diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index faa74436de5..03fb70ef2eb 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -3,8 +3,8 @@ /* * uss720.c -- USS720 USB Parport Cable. * - * Copyright (C) 1999 - * Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1999, 2005 + * Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -23,103 +23,240 @@ * Based on parport_pc.c * * History: - * 0.1 04.08.99 Created - * 0.2 07.08.99 Some fixes mainly suggested by Tim Waugh - * Interrupt handling currently disabled because - * usb_request_irq crashes somewhere within ohci.c - * for no apparent reason (that is for me, anyway) - * ECP currently untested - * 0.3 10.08.99 fixing merge errors - * 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable - * 0.5 20.09.99 usb_control_msg wrapper used - * Nov01.00 usb_device_table support by Adam J. Richter - * 08.04.01 Identify version on module load. gb + * 0.1 04.08.1999 Created + * 0.2 07.08.1999 Some fixes mainly suggested by Tim Waugh + * Interrupt handling currently disabled because + * usb_request_irq crashes somewhere within ohci.c + * for no apparent reason (that is for me, anyway) + * ECP currently untested + * 0.3 10.08.1999 fixing merge errors + * 0.4 13.08.1999 Added Vendor/Product ID of Brad Hard's cable + * 0.5 20.09.1999 usb_control_msg wrapper used + * Nov01.2000 usb_device_table support by Adam J. Richter + * 08.04.2001 Identify version on module load. gb + * 0.6 02.09.2005 Fix "scheduling in interrupt" problem by making save/restore + * context asynchronous * */ /*****************************************************************************/ +#define DEBUG + #include <linux/module.h> #include <linux/socket.h> #include <linux/parport.h> #include <linux/init.h> #include <linux/usb.h> #include <linux/delay.h> +#include <linux/completion.h> +#include <linux/kref.h> /* * Version Information */ -#define DRIVER_VERSION "v0.5" -#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch" +#define DRIVER_VERSION "v0.6" +#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch" #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" /* --------------------------------------------------------------------- */ struct parport_uss720_private { struct usb_device *usbdev; - void *irqhandle; - unsigned int irqpipe; - unsigned char reg[7]; /* USB registers */ + struct parport *pp; + struct kref ref_count; + __u8 reg[7]; /* USB registers */ + struct list_head asynclist; + spinlock_t asynclock; +}; + +struct uss720_async_request { + struct parport_uss720_private *priv; + struct kref ref_count; + struct list_head asynclist; + struct completion compl; + struct urb *urb; + struct usb_ctrlrequest dr; + __u8 reg[7]; }; /* --------------------------------------------------------------------- */ -static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val) +static void destroy_priv(struct kref *kref) { - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; - static const unsigned char regindex[9] = { - 4, 0, 1, 5, 5, 0, 2, 3, 6 - }; - int ret; + struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count); - if (!usbdev) - return -1; - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000); - if (ret != 7) { - printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n", - (unsigned int)reg, ret); - ret = -1; - } else { + usb_put_dev(priv->usbdev); + kfree(priv); + dbg("destroying priv datastructure"); +} + +static void destroy_async(struct kref *kref) +{ + struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count); + struct parport_uss720_private *priv = rq->priv; + unsigned long flags; + + if (likely(rq->urb)) + usb_free_urb(rq->urb); + spin_lock_irqsave(&priv->asynclock, flags); + list_del_init(&rq->asynclist); + spin_unlock_irqrestore(&priv->asynclock, flags); + kfree(rq); + kref_put(&priv->ref_count, destroy_priv); +} + +/* --------------------------------------------------------------------- */ + +static void async_complete(struct urb *urb, struct pt_regs *ptregs) +{ + struct uss720_async_request *rq; + struct parport *pp; + struct parport_uss720_private *priv; + + rq = urb->context; + priv = rq->priv; + pp = priv->pp; + if (urb->status) { + err("async_complete: urb error %d", urb->status); + } else if (rq->dr.bRequest == 3) { + memcpy(priv->reg, rq->reg, sizeof(priv->reg)); #if 0 - printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n", - (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], - (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], - (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]); + dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x", + (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2], + (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], + (unsigned int)priv->reg[6]); #endif /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ - if (priv->reg[2] & priv->reg[1] & 0x10) + if (rq->reg[2] & rq->reg[1] & 0x10 && pp) parport_generic_irq(0, pp, NULL); - ret = 0; } - if (val) - *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; - return ret; + complete(&rq->compl); + kref_put(&rq->ref_count, destroy_async); } -static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val) +static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, + __u8 request, __u8 requesttype, __u16 value, __u16 index, + unsigned int mem_flags) { - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; + struct usb_device *usbdev; + struct uss720_async_request *rq; + unsigned long flags; int ret; + if (!priv) + return NULL; + usbdev = priv->usbdev; if (!usbdev) - return -1; - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000); - if (ret) { - printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", - (unsigned int)reg, (unsigned int)val, ret); - } else { -#if 0 - printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", - (unsigned int)reg, (unsigned int)val); -#endif + return NULL; + rq = kmalloc(sizeof(struct uss720_async_request), mem_flags); + if (!rq) { + err("submit_async_request out of memory"); + return NULL; + } + kref_init(&rq->ref_count); + INIT_LIST_HEAD(&rq->asynclist); + init_completion(&rq->compl); + kref_get(&priv->ref_count); + rq->priv = priv; + rq->urb = usb_alloc_urb(0, mem_flags); + if (!rq->urb) { + kref_put(&rq->ref_count, destroy_async); + err("submit_async_request out of memory"); + return NULL; + } + rq->dr.bRequestType = requesttype; + rq->dr.bRequest = request; + rq->dr.wValue = cpu_to_le16(value); + rq->dr.wIndex = cpu_to_le16(index); + rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0); + usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0), + (unsigned char *)&rq->dr, + (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq); + /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */ + spin_lock_irqsave(&priv->asynclock, flags); + list_add_tail(&rq->asynclist, &priv->asynclist); + spin_unlock_irqrestore(&priv->asynclock, flags); + ret = usb_submit_urb(rq->urb, mem_flags); + if (!ret) { + kref_get(&rq->ref_count); + return rq; } + kref_put(&rq->ref_count, destroy_async); + err("submit_async_request submit_urb failed with %d", ret); + return NULL; +} + +static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv) +{ + struct uss720_async_request *rq; + unsigned long flags; + unsigned int ret = 0; + + spin_lock_irqsave(&priv->asynclock, flags); + list_for_each_entry(rq, &priv->asynclist, asynclist) { + usb_unlink_urb(rq->urb); + ret++; + } + spin_unlock_irqrestore(&priv->asynclock, flags); return ret; } /* --------------------------------------------------------------------- */ +static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags) +{ + struct parport_uss720_private *priv; + struct uss720_async_request *rq; + static const unsigned char regindex[9] = { + 4, 0, 1, 5, 5, 0, 2, 3, 6 + }; + int ret; + + if (!pp) + return -EIO; + priv = pp->private_data; + rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags); + if (!rq) { + err("get_1284_register(%u) failed", (unsigned int)reg); + return -EIO; + } + if (!val) { + kref_put(&rq->ref_count, destroy_async); + return 0; + } + if (wait_for_completion_timeout(&rq->compl, HZ)) { + ret = rq->urb->status; + *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; + if (ret) + warn("get_1284_register: usb error %d", ret); + kref_put(&rq->ref_count, destroy_async); + return ret; + } + warn("get_1284_register timeout"); + kill_all_async_requests_priv(priv); + return -EIO; +} + +static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags) +{ + struct parport_uss720_private *priv; + struct uss720_async_request *rq; + + if (!pp) + return -EIO; + priv = pp->private_data; + rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags); + if (!rq) { + err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val); + return -EIO; + } + kref_put(&rq->ref_count, destroy_async); + return 0; +} + +/* --------------------------------------------------------------------- */ + /* ECR modes */ #define ECR_SPP 00 #define ECR_PS2 01 @@ -132,8 +269,9 @@ static int change_mode(struct parport *pp, int m) { struct parport_uss720_private *priv = pp->private_data; int mode; + __u8 reg; - if (get_1284_register(pp, 6, NULL)) + if (get_1284_register(pp, 6, ®, GFP_KERNEL)) return -EIO; /* Bits <7:5> contain the mode. */ mode = (priv->reg[2] >> 5) & 0x7; @@ -153,7 +291,7 @@ static int change_mode(struct parport *pp, int m) case ECR_ECP: /* ECP Parallel Port mode */ /* Poll slowly. */ for (;;) { - if (get_1284_register(pp, 6, NULL)) + if (get_1284_register(pp, 6, ®, GFP_KERNEL)) return -EIO; if (priv->reg[2] & 0x01) break; @@ -167,7 +305,9 @@ static int change_mode(struct parport *pp, int m) } } /* Set the mode. */ - if (set_1284_register(pp, 6, m << 5)) + if (set_1284_register(pp, 6, m << 5, GFP_KERNEL)) + return -EIO; + if (get_1284_register(pp, 6, ®, GFP_KERNEL)) return -EIO; return 0; } @@ -179,7 +319,7 @@ static int clear_epp_timeout(struct parport *pp) { unsigned char stat; - if (get_1284_register(pp, 1, &stat)) + if (get_1284_register(pp, 1, &stat, GFP_KERNEL)) return 1; return stat & 1; } @@ -205,14 +345,14 @@ static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id) static void parport_uss720_write_data(struct parport *pp, unsigned char d) { - set_1284_register(pp, 0, d); + set_1284_register(pp, 0, d, GFP_KERNEL); } static unsigned char parport_uss720_read_data(struct parport *pp) { unsigned char ret; - if (get_1284_register(pp, 0, &ret)) + if (get_1284_register(pp, 0, &ret, GFP_KERNEL)) return 0; return ret; } @@ -222,7 +362,7 @@ static void parport_uss720_write_control(struct parport *pp, unsigned char d) struct parport_uss720_private *priv = pp->private_data; d = (d & 0xf) | (priv->reg[1] & 0xf0); - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; } @@ -241,7 +381,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch mask &= 0x0f; val &= 0x0f; d = (priv->reg[1] & (~mask)) ^ val; - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return 0; priv->reg[1] = d; return d & 0xf; @@ -251,7 +391,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp) { unsigned char ret; - if (get_1284_register(pp, 1, &ret)) + if (get_1284_register(pp, 1, &ret, GFP_KERNEL)) return 0; return ret & 0xf8; } @@ -262,7 +402,7 @@ static void parport_uss720_disable_irq(struct parport *pp) unsigned char d; d = priv->reg[1] & ~0x10; - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; } @@ -273,7 +413,7 @@ static void parport_uss720_enable_irq(struct parport *pp) unsigned char d; d = priv->reg[1] | 0x10; - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; } @@ -284,7 +424,7 @@ static void parport_uss720_data_forward (struct parport *pp) unsigned char d; d = priv->reg[1] & ~0x20; - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; } @@ -295,7 +435,7 @@ static void parport_uss720_data_reverse (struct parport *pp) unsigned char d; d = priv->reg[1] | 0x20; - if (set_1284_register(pp, 2, d)) + if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; } @@ -310,17 +450,23 @@ static void parport_uss720_save_state(struct parport *pp, struct parport_state * { struct parport_uss720_private *priv = pp->private_data; - if (get_1284_register(pp, 2, NULL)) +#if 0 + if (get_1284_register(pp, 2, NULL, GFP_ATOMIC)) return; +#endif s->u.pc.ctr = priv->reg[1]; s->u.pc.ecr = priv->reg[2]; } static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s) { - set_1284_register(pp, 2, s->u.pc.ctr); - set_1284_register(pp, 6, s->u.pc.ecr); - get_1284_register(pp, 2, NULL); + struct parport_uss720_private *priv = pp->private_data; + + set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC); + set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC); + get_1284_register(pp, 2, NULL, GFP_ATOMIC); + priv->reg[1] = s->u.pc.ctr; + priv->reg[2] = s->u.pc.ecr; } static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags) @@ -331,7 +477,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { - if (get_1284_register(pp, 4, (char *)buf)) + if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) break; buf++; if (priv->reg[0] & 0x01) { @@ -352,10 +498,10 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { - if (set_1284_register(pp, 4, (char *)buf)) + if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) break; ((char*)buf)++; - if (get_1284_register(pp, 1, NULL)) + if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) break; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); @@ -390,7 +536,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { - if (get_1284_register(pp, 3, (char *)buf)) + if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL)) break; buf++; if (priv->reg[0] & 0x01) { @@ -410,10 +556,10 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { - if (set_1284_register(pp, 3, *(char *)buf)) + if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL)) break; buf++; - if (get_1284_register(pp, 1, NULL)) + if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) break; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); @@ -467,7 +613,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff if (change_mode(pp, ECR_ECP)) return 0; for (; written < len; written++) { - if (set_1284_register(pp, 5, *(char *)buffer)) + if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL)) break; buffer++; } @@ -536,93 +682,91 @@ static struct parport_operations parport_uss720_ops = static int uss720_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *usbdev = interface_to_usbdev(intf); + struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf)); struct usb_host_interface *interface; struct usb_host_endpoint *endpoint; struct parport_uss720_private *priv; struct parport *pp; + unsigned char reg; int i; - printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct)); + dbg("probe: vendor id 0x%x, device id 0x%x\n", + le16_to_cpu(usbdev->descriptor.idVendor), + le16_to_cpu(usbdev->descriptor.idProduct)); /* our known interfaces have 3 alternate settings */ - if (intf->num_altsetting != 3) + if (intf->num_altsetting != 3) { + usb_put_dev(usbdev); return -ENODEV; - + } i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); - printk(KERN_DEBUG "uss720: set inteface result %d\n", i); + dbg("set inteface result %d", i); interface = intf->cur_altsetting; /* * Allocate parport interface */ - printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n"); - - if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) + if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) { + usb_put_dev(usbdev); return -ENOMEM; + } + priv->pp = NULL; + priv->usbdev = usbdev; + kref_init(&priv->ref_count); + spin_lock_init(&priv->asynclock); + INIT_LIST_HEAD(&priv->asynclist); if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) { - printk(KERN_WARNING "usb-uss720: could not register parport\n"); + warn("could not register parport"); goto probe_abort; } + priv->pp = pp; pp->private_data = priv; - priv->usbdev = usbdev; pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ - set_1284_register(pp, 7, 0x00); - set_1284_register(pp, 6, 0x30); /* PS/2 mode */ - set_1284_register(pp, 2, 0x0c); + set_1284_register(pp, 7, 0x00, GFP_KERNEL); + set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */ + set_1284_register(pp, 2, 0x0c, GFP_KERNEL); /* debugging */ - get_1284_register(pp, 0, NULL); - printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n", - priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); + get_1284_register(pp, 0, ®, GFP_KERNEL); + dbg("reg: %02x %02x %02x %02x %02x %02x %02x", + priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); endpoint = &interface->endpoint[2]; - printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); -#if 0 - priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress); - i = usb_request_irq(usbdev, priv->irqpipe, - uss720_irq, endpoint->bInterval, - pp, &priv->irqhandle); - if (i) { - printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i); - goto probe_abort_port; - } -#endif + dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); parport_announce_port(pp); - usb_set_intfdata (intf, pp); + usb_set_intfdata(intf, pp); return 0; -#if 0 -probe_abort_port: - parport_put_port(pp); -#endif probe_abort: - kfree(priv); + kill_all_async_requests_priv(priv); + kref_put(&priv->ref_count, destroy_priv); return -ENODEV; } static void uss720_disconnect(struct usb_interface *intf) { - struct parport *pp = usb_get_intfdata (intf); + struct parport *pp = usb_get_intfdata(intf); struct parport_uss720_private *priv; + struct usb_device *usbdev; - usb_set_intfdata (intf, NULL); + dbg("disconnect"); + usb_set_intfdata(intf, NULL); if (pp) { priv = pp->private_data; - parport_remove_port(pp); -#if 0 - usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe); -#endif + usbdev = priv->usbdev; priv->usbdev = NULL; + priv->pp = NULL; + dbg("parport_remove_port"); + parport_remove_port(pp); parport_put_port(pp); - kfree(priv); + kill_all_async_requests_priv(priv); + kref_put(&priv->ref_count, destroy_priv); } + dbg("disconnect done"); } /* table of cables that work through this driver */ @@ -647,8 +791,8 @@ static struct usb_driver uss720_driver = { /* --------------------------------------------------------------------- */ -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static int __init uss720_init(void) @@ -659,6 +803,9 @@ static int __init uss720_init(void) goto out; info(DRIVER_VERSION ":" DRIVER_DESC); + info("NOTE: this is a special purpose driver to allow nonstandard"); + info("protocols (eg. bitbang) over USS720 usb to parallel cables"); + info("If you just want to connect to a printer, use usblp instead"); out: return retval; } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 417464dea9f..17d0190ef64 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -79,7 +79,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, return '-'; if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) - return 'D'; + return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 4ace9964fc6..97c78c21e8d 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -32,7 +32,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.04" +#define DRIVER_VERSION "v0.05" #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" /* @@ -54,8 +54,11 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ + { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ + { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { } /* Terminating Entry */ }; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 05c44ae3ed3..9ee1aaff2fc 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -610,8 +610,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) timeout = max((HZ*2560)/bps,HZ/10); else timeout = 2*HZ; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); + schedule_timeout_interruptible(timeout); dbg("%s - stopping urbs", __FUNCTION__); usb_kill_urb (port->interrupt_in_urb); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0a6e8b474b1..4e434cb10bb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -914,7 +914,7 @@ static void ftdi_determine_type(struct usb_serial_port *port) unsigned interfaces; /* Assume it is not the original SIO device for now. */ - priv->baud_base = 48000000 / 16; + priv->baud_base = 48000000 / 2; priv->write_offset = 0; version = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 461474176cf..3cf245bdda5 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, + { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) }, { } /* Terminating entry */ }; @@ -652,8 +653,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) timeout = max((HZ*2560)/bps,HZ/10); else timeout = 2*HZ; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); + schedule_timeout_interruptible(timeout); /* shutdown our urbs */ dbg("%s - shutting down urbs", __FUNCTION__); diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index b734c4003c5..7be9644f5a0 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -58,3 +58,7 @@ #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 + +/* Nokia CA-42 Cable */ +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index d34dc9f417f..4837524eada 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -227,42 +227,42 @@ static int queuecommand(struct scsi_cmnd *srb, ***********************************************************************/ /* Command timeout and abort */ -/* This is always called with scsi_lock(host) held */ static int command_abort(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); US_DEBUGP("%s called\n", __FUNCTION__); + /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING + * bits are protected by the host lock. */ + scsi_lock(us_to_host(us)); + /* Is this command still active? */ if (us->srb != srb) { + scsi_unlock(us_to_host(us)); US_DEBUGP ("-- nothing to abort\n"); return FAILED; } /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if * a device reset isn't already in progress (to avoid interfering - * with the reset). To prevent races with auto-reset, we must - * stop any ongoing USB transfers while still holding the host - * lock. */ + * with the reset). Note that we must retain the host lock while + * calling usb_stor_stop_transport(); otherwise it might interfere + * with an auto-reset that begins as soon as we release the lock. */ set_bit(US_FLIDX_TIMED_OUT, &us->flags); if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { set_bit(US_FLIDX_ABORTING, &us->flags); usb_stor_stop_transport(us); } + scsi_unlock(us_to_host(us)); /* Wait for the aborted command to finish */ wait_for_completion(&us->notify); - - /* Reacquire the lock and allow USB transfers to resume */ - clear_bit(US_FLIDX_ABORTING, &us->flags); - clear_bit(US_FLIDX_TIMED_OUT, &us->flags); return SUCCESS; } /* This invokes the transport reset mechanism to reset the state of the * device */ -/* This is always called with scsi_lock(host) held */ static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); @@ -279,7 +279,6 @@ static int device_reset(struct scsi_cmnd *srb) } /* Simulate a SCSI bus reset by resetting the device's USB port. */ -/* This is always called with scsi_lock(host) held */ static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); @@ -291,7 +290,6 @@ static int bus_reset(struct scsi_cmnd *srb) result = usb_stor_port_reset(us); up(&(us->dev_semaphore)); - /* lock the host for the return */ return result < 0 ? FAILED : SUCCESS; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ad0cfd7a782..b79dad1b598 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -86,6 +86,16 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> + * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product) + * for USB floppies that need the SINGLE_LUN enforcement. + */ +UNUSUAL_DEV( 0x0409, 0x0040, 0x0000, 0x9999, + "NEC", + "NEC USB UF000x", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au> * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message * always fails and confuses drive. @@ -96,6 +106,13 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ +UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, + "SMSC", + "FDC GOLD-2.30", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + #ifdef CONFIG_USB_STORAGE_DPCM UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", @@ -103,6 +120,24 @@ UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), #endif +/* + * Pete Zaitcev <zaitcev@yahoo.com>, from Patrick C. F. Ernzer, bz#162559. + * The key does not actually break, but it returns zero sense which + * makes our SCSI stack to print confusing messages. + */ +UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100, + "USBest Technology", /* sold by Transcend */ + "USB Mass Storage Device", + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), + +/* Patch submitted by Daniel Drake <dsd@gentoo.org> + * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */ +UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100, + "Neuros Audio", + "USB 2.0 HD 2.5", + US_SC_DEVICE, US_PR_BULK, NULL, + US_FL_NEED_OVERRIDE ), + /* Patch submitted by Philipp Friedrich <philipp@void.at> */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, "Kyocera", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index cb4c770baf3..f9a9bfa1aef 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -392,11 +392,16 @@ SkipForAbort: /* If an abort request was received we need to signal that * the abort has finished. The proper test for this is * the TIMED_OUT flag, not srb->result == DID_ABORT, because - * a timeout/abort request might be received after all the - * USB processing was complete. */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) + * the timeout might have occurred after the command had + * already completed with a different result code. */ + if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { complete(&(us->notify)); + /* Allow USB transfers to resume */ + clear_bit(US_FLIDX_ABORTING, &us->flags); + clear_bit(US_FLIDX_TIMED_OUT, &us->flags); + } + /* finished working on this command */ us->srb = NULL; scsi_unlock(host); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 5fe182d6e4a..eb83a7874c7 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -137,7 +137,7 @@ config FONT_8x8 config FONT_8x16 bool "VGA 8x16 font" if FONTS - depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y + depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index b562f6bb9d3..42c7b8dcd22 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -33,6 +33,10 @@ endif obj-$(CONFIG_FB_STI) += sticore.o font.o +ifeq ($(CONFIG_USB_SISUSBVGA_CON),y) +obj-$(CONFIG_USB_SISUSBVGA) += font.o +endif + # Targets that kbuild needs to know about targets := promcon_tbl.c diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 7018ffffcbc..0dbc9ddb676 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -95,18 +95,18 @@ static struct pci_driver i810fb_driver = { static char *mode_option __devinitdata = NULL; static int vram __devinitdata = 4; static int bpp __devinitdata = 8; -static int mtrr __devinitdata = 0; -static int accel __devinitdata = 0; -static int hsync1 __devinitdata = 0; -static int hsync2 __devinitdata = 0; -static int vsync1 __devinitdata = 0; -static int vsync2 __devinitdata = 0; -static int xres __devinitdata = 640; -static int yres __devinitdata = 480; -static int vyres __devinitdata = 0; -static int sync __devinitdata = 0; -static int ext_vga __devinitdata = 0; -static int dcolor __devinitdata = 0; +static int mtrr __devinitdata; +static int accel __devinitdata; +static int hsync1 __devinitdata; +static int hsync2 __devinitdata; +static int vsync1 __devinitdata; +static int vsync2 __devinitdata; +static int xres __devinitdata; +static int yres __devinitdata; +static int vyres __devinitdata; +static int sync __devinitdata; +static int extvga __devinitdata; +static int dcolor __devinitdata; /*------------------------------------------------------------*/ @@ -950,7 +950,7 @@ static int i810_check_params(struct fb_var_screeninfo *var, struct fb_info *info) { struct i810fb_par *par = (struct i810fb_par *) info->par; - int line_length, vidmem, mode_valid = 0; + int line_length, vidmem, mode_valid = 0, retval = 0; u32 vyres = var->yres_virtual, vxres = var->xres_virtual; /* * Memory limit @@ -1026,10 +1026,11 @@ static int i810_check_params(struct fb_var_screeninfo *var, printk("i810fb: invalid video mode%s\n", default_sync ? "" : ". Specifying " "vsyncN/hsyncN parameters may help"); + retval = -EINVAL; } } - return 0; + return retval; } /** @@ -1724,12 +1725,21 @@ static void __devinit i810_init_defaults(struct i810fb_par *par, if (bpp < 8) bpp = 8; + par->i810fb_ops = i810fb_ops; + + if (xres) + info->var.xres = xres; + else + info->var.xres = 640; + + if (yres) + info->var.yres = yres; + else + info->var.yres = 480; + if (!vyres) - vyres = (vram << 20)/(xres*bpp >> 3); + vyres = (vram << 20)/(info->var.xres*bpp >> 3); - par->i810fb_ops = i810fb_ops; - info->var.xres = xres; - info->var.yres = yres; info->var.yres_virtual = vyres; info->var.bits_per_pixel = bpp; @@ -1756,7 +1766,7 @@ static void __devinit i810_init_device(struct i810fb_par *par) i810_init_cursor(par); /* mvo: enable external vga-connector (for laptops) */ - if (ext_vga) { + if (extvga) { i810_writel(HVSYNC, mmio, 0); i810_writel(PWR_CLKC, mmio, 3); } @@ -1830,7 +1840,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) { struct fb_videomode mode; struct fb_var_screeninfo var; - struct fb_monspecs *specs = NULL; + struct fb_monspecs *specs = &info->monspecs; int found = 0; #ifdef CONFIG_FB_I810_I2C int i; @@ -1853,16 +1863,24 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) if (!err) printk("i810fb_init_pci: DDC probe successful\n"); - fb_edid_to_monspecs(par->edid, &info->monspecs); + fb_edid_to_monspecs(par->edid, specs); - if (info->monspecs.modedb == NULL) + if (specs->modedb == NULL) printk("i810fb_init_pci: Unable to get Mode Database\n"); - specs = &info->monspecs; fb_videomode_to_modelist(specs->modedb, specs->modedb_len, &info->modelist); if (specs->modedb != NULL) { - if (specs->misc & FB_MISC_1ST_DETAIL) { + if (xres && yres) { + struct fb_videomode *m; + + if ((m = fb_find_best_mode(&var, &info->modelist))) { + mode = *m; + found = 1; + } + } + + if (!found && specs->misc & FB_MISC_1ST_DETAIL) { for (i = 0; i < specs->modedb_len; i++) { if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { mode = specs->modedb[i]; @@ -1903,8 +1921,8 @@ static int __devinit i810fb_setup(char *options) mtrr = 1; else if (!strncmp(this_opt, "accel", 5)) accel = 1; - else if (!strncmp(this_opt, "ext_vga", 7)) - ext_vga = 1; + else if (!strncmp(this_opt, "extvga", 6)) + extvga = 1; else if (!strncmp(this_opt, "sync", 4)) sync = 1; else if (!strncmp(this_opt, "vram:", 5)) @@ -2133,8 +2151,8 @@ module_param(accel, bool, 0); MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); module_param(mtrr, bool, 0); MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)"); -module_param(ext_vga, bool, 0); -MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)"); +module_param(extvga, bool, 0); +MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)"); module_param(sync, bool, 0); MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" " (default = 0)"); diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c index b7c24b34d27..279e0e0363d 100644 --- a/drivers/w1/w1_ds2433.c +++ b/drivers/w1/w1_ds2433.c @@ -15,6 +15,10 @@ #include <linux/delay.h> #ifdef CONFIG_W1_F23_CRC #include <linux/crc16.h> + +#define CRC16_INIT 0 +#define CRC16_VALID 0xb001 + #endif #include "w1.h" @@ -214,7 +218,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, #ifdef CONFIG_W1_F23_CRC /* can only write full blocks in cached mode */ if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) { - dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n", + dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n", (int)off, count); return -EINVAL; } diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index e4fd6134244..49eafbdb15c 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -34,9 +34,6 @@ ToDo/Notes: journals with two different restart pages. We sanity check both and either use the only sane one or the more recent one of the two in the case that both are valid. - - Modify fs/ntfs/malloc.h::ntfs_malloc_nofs() to do the kmalloc() based - allocations with __GFP_HIGHMEM, analogous to how the vmalloc() based - allocations are done. - Add fs/ntfs/malloc.h::ntfs_malloc_nofs_nofail() which is analogous to ntfs_malloc_nofs() but it performs allocations with __GFP_NOFAIL and hence cannot fail. @@ -90,7 +87,11 @@ ToDo/Notes: in the first buffer head instead of a driver global spin lock to improve scalability. - Minor fix to error handling and error message display in - fs/ntfs/aops.c::ntfs_prepare_nonresident_write(). + fs/ntfs/aops.c::ntfs_prepare_nonresident_write(). + - Change the mount options {u,f,d}mask to always parse the number as + an octal number to conform to how chmod(1) works, too. Thanks to + Giuseppe Bilotta and Horst von Brand for pointing out the errors of + my ways. 2.1.23 - Implement extension of resident files and make writing safe as well as many bug fixes, cleanups, and enhancements... diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 9994e019a3c..3288bcc2c4a 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h @@ -45,7 +45,7 @@ static inline void *__ntfs_malloc(unsigned long size, if (likely(size <= PAGE_SIZE)) { BUG_ON(!size); /* kmalloc() has per-CPU caches so is faster for now. */ - return kmalloc(PAGE_SIZE, gfp_mask); + return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM); /* return (void *)__get_free_page(gfp_mask); */ } if (likely(size >> PAGE_SHIFT < num_physpages)) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index b2b39296126..453d0d51ea4 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -126,6 +126,14 @@ static BOOL parse_options(ntfs_volume *vol, char *opt) if (*v) \ goto needs_val; \ } +#define NTFS_GETOPT_OCTAL(option, variable) \ + if (!strcmp(p, option)) { \ + if (!v || !*v) \ + goto needs_arg; \ + variable = simple_strtoul(ov = v, &v, 8); \ + if (*v) \ + goto needs_val; \ + } #define NTFS_GETOPT_BOOL(option, variable) \ if (!strcmp(p, option)) { \ BOOL val; \ @@ -157,9 +165,9 @@ static BOOL parse_options(ntfs_volume *vol, char *opt) *v++ = 0; NTFS_GETOPT("uid", uid) else NTFS_GETOPT("gid", gid) - else NTFS_GETOPT("umask", fmask = dmask) - else NTFS_GETOPT("fmask", fmask) - else NTFS_GETOPT("dmask", dmask) + else NTFS_GETOPT_OCTAL("umask", fmask = dmask) + else NTFS_GETOPT_OCTAL("fmask", fmask) + else NTFS_GETOPT_OCTAL("dmask", dmask) else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier) else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE) else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files) diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index faff403e106..7d0298347ee 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -23,7 +23,11 @@ * and page free order so much.. */ #ifdef CONFIG_SMP - #define FREE_PTE_NR 506 + #ifdef ARCH_FREE_PTR_NR + #define FREE_PTR_NR ARCH_FREE_PTR_NR + #else + #define FREE_PTE_NR 506 + #endif #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U) #else #define FREE_PTE_NR 1 diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 6a1b1882285..8c454aa58ac 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -130,6 +130,8 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 +extern int disable_timer_pin_1; + #else /* !CONFIG_X86_LOCAL_APIC */ static inline void lapic_shutdown(void) { } diff --git a/include/asm-i386/numa.h b/include/asm-i386/numa.h new file mode 100644 index 00000000000..96fcb157db1 --- /dev/null +++ b/include/asm-i386/numa.h @@ -0,0 +1,3 @@ + +int pxm_to_nid(int pxm); + diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 2461b731781..0ec27c9e8e4 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -60,7 +60,7 @@ static inline int node_to_first_cpu(int node) return first_cpu(mask); } -#define pcibus_to_node(bus) mp_bus_id_to_node[(bus)->number] +#define pcibus_to_node(bus) ((long) (bus)->sysdata) #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)) /* sched_domains SD_NODE_INIT for NUMAQ machines */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index a7cb377745b..fbaf90a3968 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -332,7 +332,7 @@ type name(type1 arg1) \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1))); \ + : "0" (__NR_##name),"b" ((long)(arg1)) : "memory"); \ __syscall_return(type,__res); \ } @@ -342,7 +342,7 @@ type name(type1 arg1,type2 arg2) \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)) : "memory"); \ __syscall_return(type,__res); \ } @@ -353,7 +353,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3))); \ + "d" ((long)(arg3)) : "memory"); \ __syscall_return(type,__res); \ } @@ -364,7 +364,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4))); \ + "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \ __syscall_return(type,__res); \ } @@ -376,7 +376,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) : "memory"); \ __syscall_return(type,__res); \ } @@ -389,7 +389,7 @@ __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; p : "=a" (__res) \ : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ - "0" ((long)(arg6))); \ + "0" ((long)(arg6)) : "memory"); \ __syscall_return(type,__res); \ } diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h index f95e32b4042..c42f88a9b9f 100644 --- a/include/asm-m68knommu/bitops.h +++ b/include/asm-m68knommu/bitops.h @@ -259,7 +259,7 @@ static __inline__ int __test_bit(int nr, const volatile unsigned long * addr) #define find_first_bit(addr, size) \ find_next_bit((addr), (size), 0) -static __inline__ int find_next_zero_bit (void * addr, int size, int offset) +static __inline__ int find_next_zero_bit (const void * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; diff --git a/include/asm-m68knommu/checksum.h b/include/asm-m68knommu/checksum.h index 92cf102c253..294ec7583ac 100644 --- a/include/asm-m68knommu/checksum.h +++ b/include/asm-m68knommu/checksum.h @@ -25,7 +25,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) * better 64-bit) boundary */ -unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); +unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, + int len, int sum); /* @@ -35,8 +36,8 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); * better 64-bit) boundary */ -extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, - int len, int sum, int *csum_err); +extern unsigned int csum_partial_copy_from_user(const unsigned char *src, + unsigned char *dst, int len, int sum, int *csum_err); #define csum_partial_copy_nocheck(src, dst, len, sum) \ csum_partial_copy((src), (dst), (len), (sum)) diff --git a/include/asm-m68knommu/m527xsim.h b/include/asm-m68knommu/m527xsim.h index d280d013da0..e7878d0f7d7 100644 --- a/include/asm-m68knommu/m527xsim.h +++ b/include/asm-m68knommu/m527xsim.h @@ -37,13 +37,14 @@ /* * SDRAM configuration registers. */ -#ifdef CONFIG_M5271EVB +#ifdef CONFIG_M5271 #define MCFSIM_DCR 0x40 /* SDRAM control */ #define MCFSIM_DACR0 0x48 /* SDRAM base address 0 */ #define MCFSIM_DMR0 0x4c /* SDRAM address mask 0 */ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ -#else +#endif +#ifdef CONFIG_M5275 #define MCFSIM_DMR 0x40 /* SDRAM mode */ #define MCFSIM_DCR 0x44 /* SDRAM control */ #define MCFSIM_DCFG1 0x48 /* SDRAM configuration 1 */ @@ -54,5 +55,21 @@ #define MCFSIM_DMR1 0x5c /* SDRAM address mask 1 */ #endif +/* + * GPIO pins setups to enable the UARTs. + */ +#ifdef CONFIG_M5271 +#define MCF_GPIO_PAR_UART 0x100048 /* PAR UART address */ +#define UART0_ENABLE_MASK 0x000f +#define UART1_ENABLE_MASK 0x0ff0 +#define UART2_ENABLE_MASK 0x3000 +#endif +#ifdef CONFIG_M5275 +#define MCF_GPIO_PAR_UART 0x10007c /* PAR UART address */ +#define UART0_ENABLE_MASK 0x000f +#define UART1_ENABLE_MASK 0x00f0 +#define UART2_ENABLE_MASK 0x3f00 +#endif + /****************************************************************************/ #endif /* m527xsim_h */ diff --git a/include/asm-m68knommu/m528xsim.h b/include/asm-m68knommu/m528xsim.h index 371993a206a..610774a17f7 100644 --- a/include/asm-m68knommu/m528xsim.h +++ b/include/asm-m68knommu/m528xsim.h @@ -41,5 +41,117 @@ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ +/* + * Derek Cheung - 6 Feb 2005 + * add I2C and QSPI register definition using Freescale's MCF5282 + */ +/* set Port AS pin for I2C or UART */ +#define MCF5282_GPIO_PASPAR (volatile u16 *) (MCF_IPSBAR + 0x00100056) + +/* Interrupt Mask Register Register Low */ +#define MCF5282_INTC0_IMRL (volatile u32 *) (MCF_IPSBAR + 0x0C0C) +/* Interrupt Control Register 7 */ +#define MCF5282_INTC0_ICR17 (volatile u8 *) (MCF_IPSBAR + 0x0C51) + + + +/********************************************************************* +* +* Inter-IC (I2C) Module +* +*********************************************************************/ +/* Read/Write access macros for general use */ +#define MCF5282_I2C_I2ADR (volatile u8 *) (MCF_IPSBAR + 0x0300) // Address +#define MCF5282_I2C_I2FDR (volatile u8 *) (MCF_IPSBAR + 0x0304) // Freq Divider +#define MCF5282_I2C_I2CR (volatile u8 *) (MCF_IPSBAR + 0x0308) // Control +#define MCF5282_I2C_I2SR (volatile u8 *) (MCF_IPSBAR + 0x030C) // Status +#define MCF5282_I2C_I2DR (volatile u8 *) (MCF_IPSBAR + 0x0310) // Data I/O + +/* Bit level definitions and macros */ +#define MCF5282_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) + +#define MCF5282_I2C_I2FDR_IC(x) (((x)&0x3F)) + +#define MCF5282_I2C_I2CR_IEN (0x80) // I2C enable +#define MCF5282_I2C_I2CR_IIEN (0x40) // interrupt enable +#define MCF5282_I2C_I2CR_MSTA (0x20) // master/slave mode +#define MCF5282_I2C_I2CR_MTX (0x10) // transmit/receive mode +#define MCF5282_I2C_I2CR_TXAK (0x08) // transmit acknowledge enable +#define MCF5282_I2C_I2CR_RSTA (0x04) // repeat start + +#define MCF5282_I2C_I2SR_ICF (0x80) // data transfer bit +#define MCF5282_I2C_I2SR_IAAS (0x40) // I2C addressed as a slave +#define MCF5282_I2C_I2SR_IBB (0x20) // I2C bus busy +#define MCF5282_I2C_I2SR_IAL (0x10) // aribitration lost +#define MCF5282_I2C_I2SR_SRW (0x04) // slave read/write +#define MCF5282_I2C_I2SR_IIF (0x02) // I2C interrupt +#define MCF5282_I2C_I2SR_RXAK (0x01) // received acknowledge + + + +/********************************************************************* +* +* Queued Serial Peripheral Interface (QSPI) Module +* +*********************************************************************/ +/* Derek - 21 Feb 2005 */ +/* change to the format used in I2C */ +/* Read/Write access macros for general use */ +#define MCF5282_QSPI_QMR MCF_IPSBAR + 0x0340 +#define MCF5282_QSPI_QDLYR MCF_IPSBAR + 0x0344 +#define MCF5282_QSPI_QWR MCF_IPSBAR + 0x0348 +#define MCF5282_QSPI_QIR MCF_IPSBAR + 0x034C +#define MCF5282_QSPI_QAR MCF_IPSBAR + 0x0350 +#define MCF5282_QSPI_QDR MCF_IPSBAR + 0x0354 +#define MCF5282_QSPI_QCR MCF_IPSBAR + 0x0354 + +/* Bit level definitions and macros */ +#define MCF5282_QSPI_QMR_MSTR (0x8000) +#define MCF5282_QSPI_QMR_DOHIE (0x4000) +#define MCF5282_QSPI_QMR_BITS_16 (0x0000) +#define MCF5282_QSPI_QMR_BITS_8 (0x2000) +#define MCF5282_QSPI_QMR_BITS_9 (0x2400) +#define MCF5282_QSPI_QMR_BITS_10 (0x2800) +#define MCF5282_QSPI_QMR_BITS_11 (0x2C00) +#define MCF5282_QSPI_QMR_BITS_12 (0x3000) +#define MCF5282_QSPI_QMR_BITS_13 (0x3400) +#define MCF5282_QSPI_QMR_BITS_14 (0x3800) +#define MCF5282_QSPI_QMR_BITS_15 (0x3C00) +#define MCF5282_QSPI_QMR_CPOL (0x0200) +#define MCF5282_QSPI_QMR_CPHA (0x0100) +#define MCF5282_QSPI_QMR_BAUD(x) (((x)&0x00FF)) + +#define MCF5282_QSPI_QDLYR_SPE (0x80) +#define MCF5282_QSPI_QDLYR_QCD(x) (((x)&0x007F)<<8) +#define MCF5282_QSPI_QDLYR_DTL(x) (((x)&0x00FF)) + +#define MCF5282_QSPI_QWR_HALT (0x8000) +#define MCF5282_QSPI_QWR_WREN (0x4000) +#define MCF5282_QSPI_QWR_WRTO (0x2000) +#define MCF5282_QSPI_QWR_CSIV (0x1000) +#define MCF5282_QSPI_QWR_ENDQP(x) (((x)&0x000F)<<8) +#define MCF5282_QSPI_QWR_CPTQP(x) (((x)&0x000F)<<4) +#define MCF5282_QSPI_QWR_NEWQP(x) (((x)&0x000F)) + +#define MCF5282_QSPI_QIR_WCEFB (0x8000) +#define MCF5282_QSPI_QIR_ABRTB (0x4000) +#define MCF5282_QSPI_QIR_ABRTL (0x1000) +#define MCF5282_QSPI_QIR_WCEFE (0x0800) +#define MCF5282_QSPI_QIR_ABRTE (0x0400) +#define MCF5282_QSPI_QIR_SPIFE (0x0100) +#define MCF5282_QSPI_QIR_WCEF (0x0008) +#define MCF5282_QSPI_QIR_ABRT (0x0004) +#define MCF5282_QSPI_QIR_SPIF (0x0001) + +#define MCF5282_QSPI_QAR_ADDR(x) (((x)&0x003F)) + +#define MCF5282_QSPI_QDR_COMMAND(x) (((x)&0xFF00)) +#define MCF5282_QSPI_QCR_DATA(x) (((x)&0x00FF)<<8) +#define MCF5282_QSPI_QCR_CONT (0x8000) +#define MCF5282_QSPI_QCR_BITSE (0x4000) +#define MCF5282_QSPI_QCR_DT (0x2000) +#define MCF5282_QSPI_QCR_DSCK (0x1000) +#define MCF5282_QSPI_QCR_CS (((x)&0x000F)<<8) + /****************************************************************************/ #endif /* m528xsim_h */ diff --git a/include/asm-m68knommu/mcfcache.h b/include/asm-m68knommu/mcfcache.h index bdd8c53ef34..b17cd920977 100644 --- a/include/asm-m68knommu/mcfcache.h +++ b/include/asm-m68knommu/mcfcache.h @@ -33,7 +33,7 @@ .endm #endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */ -#if defined(CONFIG_M527x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) /* * New version 2 cores have a configurable split cache arrangement. * For now I am just enabling instruction cache - but ultimately I @@ -51,23 +51,20 @@ movec %d0,%CACR /* enable cache */ nop .endm -#endif /* CONFIG_M527x */ +#endif /* CONFIG_M523x || CONFIG_M527x */ #if defined(CONFIG_M528x) -/* - * Cache is totally broken on early 5282 silicon. So far now we - * disable its cache all together. - */ .macro CACHE_ENABLE - movel #0x01000000,%d0 - movec %d0,%CACR /* invalidate cache */ nop - movel #0x0000c000,%d0 /* set SDRAM cached only */ - movec %d0,%ACR0 - movel #0x00000000,%d0 /* no other regions cached */ - movec %d0,%ACR1 - movel #0x00000000,%d0 /* configure cache */ - movec %d0,%CACR /* enable cache */ + movel #0x01000000, %d0 + movec %d0, %CACR /* Invalidate cache */ + nop + movel #0x0000c020, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + movel #0xff00c000, %d0 /* Cache Flash also */ + movec %d0, %ACR1 + movel #0x80000200, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ nop .endm #endif /* CONFIG_M528x */ diff --git a/include/asm-m68knommu/mcfdma.h b/include/asm-m68knommu/mcfdma.h index 350c6090b5c..b93f8ba8a24 100644 --- a/include/asm-m68knommu/mcfdma.h +++ b/include/asm-m68knommu/mcfdma.h @@ -21,7 +21,7 @@ #define MCFDMA_BASE1 0x240 /* Base address of DMA 1 */ #elif defined(CONFIG_M5272) #define MCFDMA_BASE0 0x0e0 /* Base address of DMA 0 */ -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* These are relative to the IPSBAR, not MBAR */ #define MCFDMA_BASE0 0x100 /* Base address of DMA 0 */ #define MCFDMA_BASE1 0x140 /* Base address of DMA 1 */ diff --git a/include/asm-powerpc/siginfo.h b/include/asm-powerpc/siginfo.h index 538ea8ef509..12f1bce037b 100644 --- a/include/asm-powerpc/siginfo.h +++ b/include/asm-powerpc/siginfo.h @@ -15,4 +15,12 @@ #include <asm-generic/siginfo.h> +/* + * SIGTRAP si_codes + */ +#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ +#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ +#undef NSIGTRAP +#define NSIGTRAP 4 + #endif /* _ASM_POWERPC_SIGINFO_H */ diff --git a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h index 9d4e4ea530c..7043c164b53 100644 --- a/include/asm-ppc/ptrace.h +++ b/include/asm-ppc/ptrace.h @@ -142,4 +142,11 @@ do { \ #define PTRACE_GETEVRREGS 20 #define PTRACE_SETEVRREGS 21 +/* + * Get or set a debug register. The first 16 are DABR registers and the + * second 16 are IABR registers. + */ +#define PTRACE_GET_DEBUGREG 25 +#define PTRACE_SET_DEBUGREG 26 + #endif diff --git a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h index 4f668a4baff..ab7c3cf2488 100644 --- a/include/asm-ppc64/hvcall.h +++ b/include/asm-ppc64/hvcall.h @@ -56,6 +56,11 @@ #define H_PP1 (1UL<<(63-62)) #define H_PP2 (1UL<<(63-63)) +/* DABRX flags */ +#define H_DABRX_HYPERVISOR (1UL<<(63-61)) +#define H_DABRX_KERNEL (1UL<<(63-62)) +#define H_DABRX_USER (1UL<<(63-63)) + /* pSeries hypervisor opcodes */ #define H_REMOVE 0x04 #define H_ENTER 0x08 @@ -101,6 +106,7 @@ #define H_VIO_SIGNAL 0x104 #define H_SEND_CRQ 0x108 #define H_COPY_RDMA 0x110 +#define H_SET_XDABR 0x134 #define H_STUFF_TCE 0x138 #define H_PUT_TCE_INDIRECT 0x13C #define H_VTERM_PARTNER_INFO 0x150 diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 9a1ef4427ed..8027160ec96 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -88,6 +88,7 @@ struct machdep_calls { /* PCI stuff */ void (*pcibios_fixup)(void); + int (*pci_probe_mode)(struct pci_bus *); void (*restart)(char *cmd); void (*power_off)(void); @@ -173,10 +174,6 @@ extern sys_ctrler_t sys_ctrler; void ppc64_boot_msg(unsigned int src, const char *msg); /* Print a termination message (print only -- does not stop the kernel) */ void ppc64_terminate_msg(unsigned int src, const char *msg); -/* Print something that needs attention (device error, etc) */ -void ppc64_attention_msg(unsigned int src, const char *msg); -/* Print a dump progress message. */ -void ppc64_dump_msg(unsigned int src, const char *msg); static inline void log_error(char *buf, unsigned int err_type, int fatal) { diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 6b4a5b1f695..d8991389ab3 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -119,5 +119,10 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) return PCI_DN(busdn)->phb; } +/* Return values for ppc_md.pci_probe_mode function */ +#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */ +#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ +#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */ + #endif #endif /* __KERNEL__ */ diff --git a/include/asm-ppc64/plpar_wrappers.h b/include/asm-ppc64/plpar_wrappers.h index f4a5fb7d67c..72dd2449ee7 100644 --- a/include/asm-ppc64/plpar_wrappers.h +++ b/include/asm-ppc64/plpar_wrappers.h @@ -107,5 +107,14 @@ static inline long plpar_put_term_char(unsigned long termno, lbuf[1]); } +static inline long plpar_set_xdabr(unsigned long address, unsigned long flags) +{ + return plpar_hcall_norets(H_SET_XDABR, address, flags); +} + +static inline long plpar_set_dabr(unsigned long val) +{ + return plpar_hcall_norets(H_SET_DABR, val); +} #endif /* _PPC64_PLPAR_WRAPPERS_H */ diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 8bd7aa95938..4146189006e 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -433,6 +433,7 @@ struct thread_struct { unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ unsigned long vdso_base; /* base of the vDSO library */ + unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute((aligned(16))); diff --git a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h index af03547f9c7..b1babb72967 100644 --- a/include/asm-ppc64/ptrace-common.h +++ b/include/asm-ppc64/ptrace-common.h @@ -11,6 +11,10 @@ #ifndef _PPC64_PTRACE_COMMON_H #define _PPC64_PTRACE_COMMON_H + +#include <linux/config.h> +#include <asm/system.h> + /* * Set of msr bits that gdb can change on behalf of a process. */ @@ -69,4 +73,92 @@ static inline void clear_single_step(struct task_struct *task) clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); } +#ifdef CONFIG_ALTIVEC +/* + * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. + * The transfer totals 34 quadword. Quadwords 0-31 contain the + * corresponding vector registers. Quadword 32 contains the vscr as the + * last word (offset 12) within that quadword. Quadword 33 contains the + * vrsave as the first word (offset 0) within the quadword. + * + * This definition of the VMX state is compatible with the current PPC32 + * ptrace interface. This allows signal handling and ptrace to use the + * same structures. This also simplifies the implementation of a bi-arch + * (combined (32- and 64-bit) gdb. + */ + +/* + * Get contents of AltiVec register state in task TASK + */ +static inline int get_vrregs(unsigned long __user *data, + struct task_struct *task) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_to_user(data, task->thread.vr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_to_user(data, &task->thread.vscr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (put_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} + +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, + unsigned long __user *data) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_from_user(task->thread.vr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_from_user(&task->thread.vscr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (get_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} +#endif + +static inline int ptrace_set_debugreg(struct task_struct *task, + unsigned long addr, unsigned long data) +{ + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + return -EINVAL; + + /* The bottom 3 bits are flags */ + if ((data & ~0x7UL) >= TASK_SIZE) + return -EIO; + + /* Ensure translation is on */ + if (data && !(data & DABR_TRANSLATION)) + return -EIO; + + task->thread.dabr = data; + return 0; +} + #endif /* _PPC64_PTRACE_COMMON_H */ diff --git a/include/asm-ppc64/ptrace.h b/include/asm-ppc64/ptrace.h index c96aad28fc0..3a55377f1fd 100644 --- a/include/asm-ppc64/ptrace.h +++ b/include/asm-ppc64/ptrace.h @@ -25,56 +25,49 @@ */ #ifndef __ASSEMBLY__ -#define PPC_REG unsigned long + struct pt_regs { - PPC_REG gpr[32]; - PPC_REG nip; - PPC_REG msr; - PPC_REG orig_gpr3; /* Used for restarting system calls */ - PPC_REG ctr; - PPC_REG link; - PPC_REG xer; - PPC_REG ccr; - PPC_REG softe; /* Soft enabled/disabled */ - PPC_REG trap; /* Reason for being here */ - PPC_REG dar; /* Fault registers */ - PPC_REG dsisr; - PPC_REG result; /* Result of a system call */ + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long softe; /* Soft enabled/disabled */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ }; -#define PPC_REG_32 unsigned int struct pt_regs32 { - PPC_REG_32 gpr[32]; - PPC_REG_32 nip; - PPC_REG_32 msr; - PPC_REG_32 orig_gpr3; /* Used for restarting system calls */ - PPC_REG_32 ctr; - PPC_REG_32 link; - PPC_REG_32 xer; - PPC_REG_32 ccr; - PPC_REG_32 mq; /* 601 only (not used at present) */ - /* Used on APUS to hold IPL value. */ - PPC_REG_32 trap; /* Reason for being here */ - PPC_REG_32 dar; /* Fault registers */ - PPC_REG_32 dsisr; - PPC_REG_32 result; /* Result of a system call */ + unsigned int gpr[32]; + unsigned int nip; + unsigned int msr; + unsigned int orig_gpr3; /* Used for restarting system calls */ + unsigned int ctr; + unsigned int link; + unsigned int xer; + unsigned int ccr; + unsigned int mq; /* 601 only (not used at present) */ + unsigned int trap; /* Reason for being here */ + unsigned int dar; /* Fault registers */ + unsigned int dsisr; + unsigned int result; /* Result of a system call */ }; +#ifdef __KERNEL__ + #define instruction_pointer(regs) ((regs)->nip) + #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); #else #define profile_pc(regs) instruction_pointer(regs) #endif -#endif /* __ASSEMBLY__ */ - -#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ - -/* Size of dummy stack frame allocated when calling signal handler. */ -#define __SIGNAL_FRAMESIZE 128 -#define __SIGNAL_FRAMESIZE32 64 - #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define force_successful_syscall_return() \ @@ -89,6 +82,16 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define TRAP(regs) ((regs)->trap & ~0xF) #define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1) +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ + +/* Size of dummy stack frame allocated when calling signal handler. */ +#define __SIGNAL_FRAMESIZE 128 +#define __SIGNAL_FRAMESIZE32 64 + /* * Offsets used by 'ptrace' system call interface. */ @@ -135,17 +138,21 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PT_XER 37 #define PT_CCR 38 #define PT_SOFTE 39 +#define PT_TRAP 40 +#define PT_DAR 41 +#define PT_DSISR 42 #define PT_RESULT 43 #define PT_FPR0 48 -/* Kernel and userspace will both use this PT_FPSCR value. 32-bit apps will have - * visibility to the asm-ppc/ptrace.h header instead of this one. +/* + * Kernel and userspace will both use this PT_FPSCR value. 32-bit apps will + * have visibility to the asm-ppc/ptrace.h header instead of this one. */ -#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ +#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ #ifdef __KERNEL__ -#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1) /* each FP reg occupies 2 32-bit userspace slots */ +#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1) /* each FP reg occupies 2 32-bit userspace slots */ #endif #define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */ @@ -173,17 +180,34 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PTRACE_GETVRREGS 18 #define PTRACE_SETVRREGS 19 -/* Additional PTRACE requests implemented on PowerPC. */ -#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ -#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ -#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */ -#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */ -#define PPC_PTRACE_PEEKTEXT_3264 0x95 /* Read word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_PEEKDATA_3264 0x94 /* Read word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKETEXT_3264 0x93 /* Write word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKEDATA_3264 0x92 /* Write word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_PEEKUSR_3264 0x91 /* Read a register (specified by ADDR) out of the "user area" on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKEUSR_3264 0x90 /* Write DATA into location ADDR within the "user area" on a 64-bit process from a 32-bit process. */ +/* + * While we dont have 64bit book E processors, we need to reserve the + * relevant ptrace calls for 32bit compatibility. + */ +#if 0 +#define PTRACE_GETEVRREGS 20 +#define PTRACE_SETEVRREGS 21 +#endif +/* + * Get or set a debug register. The first 16 are DABR registers and the + * second 16 are IABR registers. + */ +#define PTRACE_GET_DEBUGREG 25 +#define PTRACE_SET_DEBUGREG 26 + +/* Additional PTRACE requests implemented on PowerPC. */ +#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ +#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ +#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */ +#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */ + +/* Calls to trace a 64bit program from a 32bit program */ +#define PPC_PTRACE_PEEKTEXT_3264 0x95 +#define PPC_PTRACE_PEEKDATA_3264 0x94 +#define PPC_PTRACE_POKETEXT_3264 0x93 +#define PPC_PTRACE_POKEDATA_3264 0x92 +#define PPC_PTRACE_PEEKUSR_3264 0x91 +#define PPC_PTRACE_POKEUSR_3264 0x90 #endif /* _PPC64_PTRACE_H */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index c0396428cc3..375015c62f2 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -101,6 +101,9 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } #endif +extern int set_dabr(unsigned long dabr); +extern void _exception(int signr, struct pt_regs *regs, int code, + unsigned long addr); extern int fix_alignment(struct pt_regs *regs); extern void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig); diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index 16ec82e16b2..6c5d5ca8383 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -109,9 +109,10 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 +extern int disable_timer_pin_1; + #endif /* CONFIG_X86_LOCAL_APIC */ -#define esr_disable 0 extern unsigned boot_cpu_id; #endif /* __ASM_APIC_H */ diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h index 9388062c4f6..fb1c99ac669 100644 --- a/include/asm-x86_64/apicdef.h +++ b/include/asm-x86_64/apicdef.h @@ -113,6 +113,7 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) #define MAX_IO_APICS 128 +#define MAX_LOCAL_APIC 256 /* * All x86-64 systems are xAPIC compatible. diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h index eed78566728..80ac1fe966a 100644 --- a/include/asm-x86_64/bug.h +++ b/include/asm-x86_64/bug.h @@ -9,10 +9,8 @@ */ struct bug_frame { unsigned char ud2[2]; - unsigned char mov; - /* should use 32bit offset instead, but the assembler doesn't - like it */ - char *filename; + unsigned char push; + signed int filename; unsigned char ret; unsigned short line; } __attribute__((packed)); @@ -25,8 +23,8 @@ struct bug_frame { The magic numbers generate mov $64bitimm,%eax ; ret $offset. */ #define BUG() \ asm volatile( \ - "ud2 ; .byte 0xa3 ; .quad %c1 ; .byte 0xc2 ; .short %c0" :: \ - "i"(__LINE__), "i" (__stringify(__FILE__))) + "ud2 ; pushq $%c1 ; ret $%c0" :: \ + "i"(__LINE__), "i" (__FILE__)) void out_of_line_bug(void); #else static inline void out_of_line_bug(void) { } diff --git a/include/asm-x86_64/calling.h b/include/asm-x86_64/calling.h index 0bc12655fa5..fc2c5a6c262 100644 --- a/include/asm-x86_64/calling.h +++ b/include/asm-x86_64/calling.h @@ -65,27 +65,36 @@ .if \skipr11 .else movq (%rsp),%r11 + CFI_RESTORE r11 .endif .if \skipr8910 .else movq 1*8(%rsp),%r10 + CFI_RESTORE r10 movq 2*8(%rsp),%r9 + CFI_RESTORE r9 movq 3*8(%rsp),%r8 + CFI_RESTORE r8 .endif .if \skiprax .else movq 4*8(%rsp),%rax + CFI_RESTORE rax .endif .if \skiprcx .else movq 5*8(%rsp),%rcx + CFI_RESTORE rcx .endif .if \skiprdx .else movq 6*8(%rsp),%rdx + CFI_RESTORE rdx .endif movq 7*8(%rsp),%rsi + CFI_RESTORE rsi movq 8*8(%rsp),%rdi + CFI_RESTORE rdi .if ARG_SKIP+\addskip > 0 addq $ARG_SKIP+\addskip,%rsp CFI_ADJUST_CFA_OFFSET -(ARG_SKIP+\addskip) @@ -124,11 +133,17 @@ .macro RESTORE_REST movq (%rsp),%r15 + CFI_RESTORE r15 movq 1*8(%rsp),%r14 + CFI_RESTORE r14 movq 2*8(%rsp),%r13 + CFI_RESTORE r13 movq 3*8(%rsp),%r12 + CFI_RESTORE r12 movq 4*8(%rsp),%rbp + CFI_RESTORE rbp movq 5*8(%rsp),%rbx + CFI_RESTORE rbx addq $REST_SKIP,%rsp CFI_ADJUST_CFA_OFFSET -(REST_SKIP) .endm @@ -146,11 +161,3 @@ .macro icebp .byte 0xf1 .endm - -#ifdef CONFIG_FRAME_POINTER -#define ENTER enter -#define LEAVE leave -#else -#define ENTER -#define LEAVE -#endif diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h index c89b58bebee..594e610f4a1 100644 --- a/include/asm-x86_64/desc.h +++ b/include/asm-x86_64/desc.h @@ -191,7 +191,7 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu) /* * load one particular LDT into the current CPU */ -extern inline void load_LDT_nolock (mm_context_t *pc, int cpu) +static inline void load_LDT_nolock (mm_context_t *pc, int cpu) { int count = pc->size; diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h index a416dc31634..e784fdc524f 100644 --- a/include/asm-x86_64/dma-mapping.h +++ b/include/asm-x86_64/dma-mapping.h @@ -85,6 +85,11 @@ static inline void dma_sync_single_for_device(struct device *hwdev, flush_write_buffers(); } +#define dma_sync_single_range_for_cpu(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_cpu(dev, dma_handle, size, dir) +#define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_device(dev, dma_handle, size, dir) + static inline void dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg, int nelems, int direction) diff --git a/include/asm-x86_64/dwarf2.h b/include/asm-x86_64/dwarf2.h index afd4212e860..582757fc036 100644 --- a/include/asm-x86_64/dwarf2.h +++ b/include/asm-x86_64/dwarf2.h @@ -24,6 +24,10 @@ #define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset #define CFI_OFFSET .cfi_offset #define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_REGISTER .cfi_register +#define CFI_RESTORE .cfi_restore +#define CFI_REMEMBER_STATE .cfi_remember_state +#define CFI_RESTORE_STATE .cfi_restore_state #else @@ -36,6 +40,10 @@ #define CFI_ADJUST_CFA_OFFSET # #define CFI_OFFSET # #define CFI_REL_OFFSET # +#define CFI_REGISTER # +#define CFI_RESTORE # +#define CFI_REMEMBER_STATE # +#define CFI_RESTORE_STATE # #endif diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h index cf8b16cbe8d..a582cfcf223 100644 --- a/include/asm-x86_64/fixmap.h +++ b/include/asm-x86_64/fixmap.h @@ -76,7 +76,7 @@ extern void __this_fixmap_does_not_exist(void); * directly without translation, we catch the bug with a NULL-deference * kernel oops. Illegal ranges of incoming indices are caught too. */ -extern inline unsigned long fix_to_virt(const unsigned int idx) +static inline unsigned long fix_to_virt(const unsigned int idx) { /* * this branch gets completely eliminated after inlining, diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h index 27c381fa1c9..8661b476fb4 100644 --- a/include/asm-x86_64/hardirq.h +++ b/include/asm-x86_64/hardirq.h @@ -9,11 +9,12 @@ #define __ARCH_IRQ_STAT 1 -/* Generate a lvalue for a pda member. Should fix softirq.c instead to use - special access macros. This would generate better code. */ -#define __IRQ_STAT(cpu,member) (read_pda(me)->member) +#define local_softirq_pending() read_pda(__softirq_pending) -#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ +#define __ARCH_SET_SOFTIRQ_PENDING 1 + +#define set_softirq_pending(x) write_pda(__softirq_pending, (x)) +#define or_softirq_pending(x) or_pda(__softirq_pending, (x)) /* * 'what should we do if we get a hw irq event on an illegal vector'. diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 2b5cb2865d2..dc97668ea0f 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -26,6 +26,7 @@ struct hw_interrupt_type; #endif +#define NMI_VECTOR 0x02 /* * IDT vectors usable for external interrupt sources start * at 0x20: @@ -50,14 +51,15 @@ struct hw_interrupt_type; */ #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define RESCHEDULE_VECTOR 0xfc -#define TASK_MIGRATION_VECTOR 0xfb -#define CALL_FUNCTION_VECTOR 0xfa -#define KDB_VECTOR 0xf9 - -#define THERMAL_APIC_VECTOR 0xf0 - +#define RESCHEDULE_VECTOR 0xfd +#define CALL_FUNCTION_VECTOR 0xfc +#define KDB_VECTOR 0xfb /* reserved for KDB */ +#define THERMAL_APIC_VECTOR 0xfa +/* 0xf9 free */ +#define INVALIDATE_TLB_VECTOR_END 0xf8 +#define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f8 used for TLB flush */ + +#define NUM_INVALIDATE_TLB_VECTORS 8 /* * Local APIC timer IRQ vector is on a different priority level, diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index 37fc3f149a5..52ff269fe05 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -48,7 +48,7 @@ * Talk about misusing macros.. */ #define __OUT1(s,x) \ -extern inline void out##s(unsigned x value, unsigned short port) { +static inline void out##s(unsigned x value, unsigned short port) { #define __OUT2(s,s1,s2) \ __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" @@ -58,7 +58,7 @@ __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ #define __IN1(s) \ -extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; +static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; #define __IN2(s,s1,s2) \ __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" @@ -68,12 +68,12 @@ __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ #define __INS(s) \ -extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +static inline void ins##s(unsigned short port, void * addr, unsigned long count) \ { __asm__ __volatile__ ("rep ; ins" #s \ : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } #define __OUTS(s) \ -extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ { __asm__ __volatile__ ("rep ; outs" #s \ : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } @@ -110,12 +110,12 @@ __OUTS(l) * Change virtual addresses to physical addresses and vv. * These are pretty trivial */ -extern inline unsigned long virt_to_phys(volatile void * address) +static inline unsigned long virt_to_phys(volatile void * address) { return __pa(address); } -extern inline void * phys_to_virt(unsigned long address) +static inline void * phys_to_virt(unsigned long address) { return __va(address); } @@ -130,7 +130,7 @@ extern inline void * phys_to_virt(unsigned long address) extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags); -extern inline void __iomem * ioremap (unsigned long offset, unsigned long size) +static inline void __iomem * ioremap (unsigned long offset, unsigned long size) { return __ioremap(offset, size, 0); } diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h index 5e166b9d3bd..022e9d340ad 100644 --- a/include/asm-x86_64/ipi.h +++ b/include/asm-x86_64/ipi.h @@ -31,9 +31,20 @@ static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest) { - unsigned int icr = APIC_DM_FIXED | shortcut | vector | dest; - if (vector == KDB_VECTOR) - icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI; + unsigned int icr = shortcut | dest; + + switch (vector) { + default: + icr |= APIC_DM_FIXED | vector; + break; + case NMI_VECTOR: + /* + * Setup KDB IPI to be delivered as an NMI + */ + case KDB_VECTOR: + icr |= APIC_DM_NMI; + break; + } return icr; } @@ -66,7 +77,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsign /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); } @@ -92,7 +103,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) * prepare target chip field */ cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]); - apic_write_around(APIC_ICR2, cfg); + apic_write(APIC_ICR2, cfg); /* * program the ICR @@ -102,7 +113,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); } local_irq_restore(flags); } diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b90341994d8..f604e84c530 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h @@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long); extern void __die(const char *,struct pt_regs *,long); extern void show_registers(struct pt_regs *regs); extern void dump_pagetable(unsigned long); -extern void oops_begin(void); -extern void oops_end(void); +extern unsigned long oops_begin(void); +extern void oops_end(unsigned long); #endif diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h index c954f15c1a7..3e72c41727c 100644 --- a/include/asm-x86_64/local.h +++ b/include/asm-x86_64/local.h @@ -29,7 +29,7 @@ static __inline__ void local_dec(local_t *v) :"m" (v->counter)); } -static __inline__ void local_add(unsigned long i, local_t *v) +static __inline__ void local_add(unsigned int i, local_t *v) { __asm__ __volatile__( "addl %1,%0" @@ -37,7 +37,7 @@ static __inline__ void local_add(unsigned long i, local_t *v) :"ir" (i), "m" (v->counter)); } -static __inline__ void local_sub(unsigned long i, local_t *v) +static __inline__ void local_sub(unsigned int i, local_t *v) { __asm__ __volatile__( "subl %1,%0" diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index 768413751b3..b40c661f111 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -12,7 +12,7 @@ #include <asm/smp.h> -#define NODEMAPSIZE 0xff +#define NODEMAPSIZE 0xfff /* Simple perfect hash to map physical addresses to node numbers */ extern int memnode_shift; @@ -54,7 +54,7 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) #define pfn_valid(pfn) ((pfn) >= num_physpages ? 0 : \ ({ u8 nid__ = pfn_to_nid(pfn); \ - nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) <= node_end_pfn(nid__); })) + nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) < node_end_pfn(nid__); })) #endif #define local_mapnr(kvaddr) \ diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h index ba15279a79d..4d727f3f555 100644 --- a/include/asm-x86_64/msr.h +++ b/include/asm-x86_64/msr.h @@ -29,22 +29,37 @@ #define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) /* wrmsr with exception handling */ -#define wrmsr_safe(msr,a,b) ({ int ret__; \ - asm volatile("2: wrmsr ; xorl %0,%0\n" \ - "1:\n\t" \ - ".section .fixup,\"ax\"\n\t" \ - "3: movl %4,%0 ; jmp 1b\n\t" \ - ".previous\n\t" \ - ".section __ex_table,\"a\"\n" \ - " .align 8\n\t" \ - " .quad 2b,3b\n\t" \ - ".previous" \ - : "=a" (ret__) \ - : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\ +#define wrmsr_safe(msr,a,b) ({ int ret__; \ + asm volatile("2: wrmsr ; xorl %0,%0\n" \ + "1:\n\t" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl %4,%0 ; jmp 1b\n\t" \ + ".previous\n\t" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n\t" \ + " .quad 2b,3b\n\t" \ + ".previous" \ + : "=a" (ret__) \ + : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \ ret__; }) #define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32)) +#define rdmsr_safe(msr,a,b) \ + ({ int ret__; \ + asm volatile ("1: rdmsr\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %4,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n" \ + " .quad 1b,3b\n" \ + ".previous":"=&bDS" (ret__), "=a"(a), "=d"(b)\ + :"c"(msr), "i"(-EIO), "0"(0)); \ + ret__; }) + #define rdtsc(low,high) \ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) @@ -64,7 +79,7 @@ : "=a" (low), "=d" (high) \ : "c" (counter)) -extern inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, +static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { __asm__("cpuid" @@ -90,7 +105,7 @@ static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, /* * CPUID functions returning a single datum */ -extern inline unsigned int cpuid_eax(unsigned int op) +static inline unsigned int cpuid_eax(unsigned int op) { unsigned int eax; @@ -100,7 +115,7 @@ extern inline unsigned int cpuid_eax(unsigned int op) : "bx", "cx", "dx"); return eax; } -extern inline unsigned int cpuid_ebx(unsigned int op) +static inline unsigned int cpuid_ebx(unsigned int op) { unsigned int eax, ebx; @@ -110,7 +125,7 @@ extern inline unsigned int cpuid_ebx(unsigned int op) : "cx", "dx" ); return ebx; } -extern inline unsigned int cpuid_ecx(unsigned int op) +static inline unsigned int cpuid_ecx(unsigned int op) { unsigned int eax, ecx; @@ -120,7 +135,7 @@ extern inline unsigned int cpuid_ecx(unsigned int op) : "bx", "dx" ); return ecx; } -extern inline unsigned int cpuid_edx(unsigned int op) +static inline unsigned int cpuid_edx(unsigned int op) { unsigned int eax, edx; diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h index 5c363a1482e..bcf55c3f7f7 100644 --- a/include/asm-x86_64/numa.h +++ b/include/asm-x86_64/numa.h @@ -9,6 +9,7 @@ struct node { }; extern int compute_hash_shift(struct node *nodes, int numnodes); +extern int pxm_to_node(int nid); #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) @@ -16,6 +17,8 @@ extern void numa_add_cpu(int cpu); extern void numa_init_array(void); extern int numa_off; +extern unsigned char apicid_to_node[256]; + #define NUMA_NO_NODE 0xff #endif diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index 135ffaa0393..e5ab4d231f2 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h @@ -32,6 +32,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +extern unsigned long end_pfn; + void clear_page(void *); void copy_page(void *, void *); @@ -111,7 +113,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifdef CONFIG_FLATMEM #define pfn_to_page(pfn) (mem_map + (pfn)) #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) -#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define pfn_valid(pfn) ((pfn) < end_pfn) #endif #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h index eeb3088a1c9..5a82a6762c2 100644 --- a/include/asm-x86_64/pci.h +++ b/include/asm-x86_64/pci.h @@ -50,10 +50,10 @@ extern int iommu_setup(char *opt); * address space. The networking and block device layers use * this boolean for bounce buffer decisions * - * On AMD64 it mostly equals, but we set it to zero to tell some subsystems - * that an IOMMU is available. + * On x86-64 it mostly equals, but we set it to zero to tell some subsystems + * that an hard or soft IOMMU is available. */ -#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0) +#define PCI_DMA_BUS_IS_PHYS 0 /* * x86-64 always supports DAC, but sometimes it is useful to force diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h index 36b766cfc4d..bbf89aa8a1a 100644 --- a/include/asm-x86_64/pda.h +++ b/include/asm-x86_64/pda.h @@ -10,10 +10,8 @@ struct x8664_pda { struct task_struct *pcurrent; /* Current process */ unsigned long data_offset; /* Per cpu data offset from linker address */ - struct x8664_pda *me; /* Pointer to itself */ unsigned long kernelstack; /* top of kernel stack for current */ unsigned long oldrsp; /* user rsp for system call */ - unsigned long irqrsp; /* Old rsp for interrupts. */ int irqcount; /* Irq nesting counter. Starts with -1 */ int cpunumber; /* Logical CPU number */ char *irqstackptr; /* top of irqstack */ @@ -22,7 +20,7 @@ struct x8664_pda { struct mm_struct *active_mm; int mmu_state; unsigned apic_timer_irqs; -} ____cacheline_aligned; +} ____cacheline_aligned_in_smp; #define IRQSTACK_ORDER 2 @@ -42,13 +40,14 @@ extern void __bad_pda_field(void); #define pda_offset(field) offsetof(struct x8664_pda, field) #define pda_to_op(op,field,val) do { \ + typedef typeof_field(struct x8664_pda, field) T__; \ switch (sizeof_field(struct x8664_pda, field)) { \ case 2: \ -asm volatile(op "w %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ case 4: \ -asm volatile(op "l %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ case 8: \ -asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ default: __bad_pda_field(); \ } \ } while (0) @@ -58,7 +57,7 @@ asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); bre * Unfortunately removing them causes all hell to break lose currently. */ #define pda_from_op(op,field) ({ \ - typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \ + typeof_field(struct x8664_pda, field) ret__; \ switch (sizeof_field(struct x8664_pda, field)) { \ case 2: \ asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\ @@ -75,6 +74,7 @@ asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); b #define write_pda(field,val) pda_to_op("mov",field,val) #define add_pda(field,val) pda_to_op("add",field,val) #define sub_pda(field,val) pda_to_op("sub",field,val) +#define or_pda(field,val) pda_to_op("or",field,val) #endif diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h index deadd146978..08cad2482bc 100644 --- a/include/asm-x86_64/pgalloc.h +++ b/include/asm-x86_64/pgalloc.h @@ -18,12 +18,12 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); } -extern __inline__ pmd_t *get_pmd(void) +static inline pmd_t *get_pmd(void) { return (pmd_t *)get_zeroed_page(GFP_KERNEL); } -extern __inline__ void pmd_free(pmd_t *pmd) +static inline void pmd_free(pmd_t *pmd) { BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); free_page((unsigned long)pmd); @@ -86,13 +86,13 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add /* Should really implement gc for free page table pages. This could be done with a reference count in struct page. */ -extern __inline__ void pte_free_kernel(pte_t *pte) +static inline void pte_free_kernel(pte_t *pte) { BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); free_page((unsigned long)pte); } -extern inline void pte_free(struct page *pte) +static inline void pte_free(struct page *pte) { __free_page(pte); } diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 5e0f2fdab0d..1dc110ba82d 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -85,7 +85,7 @@ static inline void set_pud(pud_t *dst, pud_t val) pud_val(*dst) = pud_val(val); } -extern inline void pud_clear (pud_t *pud) +static inline void pud_clear (pud_t *pud) { set_pud(pud, __pud(0)); } @@ -95,7 +95,7 @@ static inline void set_pgd(pgd_t *dst, pgd_t val) pgd_val(*dst) = pgd_val(val); } -extern inline void pgd_clear (pgd_t * pgd) +static inline void pgd_clear (pgd_t * pgd) { set_pgd(pgd, __pgd(0)); } @@ -375,7 +375,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) } /* Change flags of a PTE */ -extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) &= _PAGE_CHG_MASK; pte_val(pte) |= pgprot_val(newprot); diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index a8321999448..03837d34fba 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -254,7 +254,13 @@ struct thread_struct { u64 tls_array[GDT_ENTRY_TLS_ENTRIES]; } __attribute__((aligned(16))); -#define INIT_THREAD {} +#define INIT_THREAD { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ +} + +#define INIT_TSS { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ +} #define INIT_MMAP \ { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } @@ -375,13 +381,13 @@ struct extended_sigtable { #define ASM_NOP_MAX 8 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ -extern inline void rep_nop(void) +static inline void rep_nop(void) { __asm__ __volatile__("rep;nop": : :"memory"); } /* Stop speculative execution */ -extern inline void sync_core(void) +static inline void sync_core(void) { int tmp; asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory"); diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index f7574196424..dbb37b0adb4 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void); extern void swap_low_mappings(void); -extern void oops_begin(void); -extern void die(const char *,struct pt_regs *,long); -extern void __die(const char * str, struct pt_regs * regs, long err); extern void __show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs); @@ -93,8 +90,6 @@ extern int unhandled_signal(struct task_struct *tsk, int sig); extern void select_idle_routine(const struct cpuinfo_x86 *c); extern void swiotlb_init(void); -extern unsigned long max_mapnr; -extern unsigned long end_pfn; extern unsigned long table_start, table_end; extern int exception_trace; diff --git a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h index fe9b96d9481..f8d55798535 100644 --- a/include/asm-x86_64/signal.h +++ b/include/asm-x86_64/signal.h @@ -143,23 +143,23 @@ typedef struct sigaltstack { #undef __HAVE_ARCH_SIG_BITOPS #if 0 -extern __inline__ void sigaddset(sigset_t *set, int _sig) +static inline void sigaddset(sigset_t *set, int _sig) { __asm__("btsq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } -extern __inline__ void sigdelset(sigset_t *set, int _sig) +static inline void sigdelset(sigset_t *set, int _sig) { __asm__("btrq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } -extern __inline__ int __const_sigismember(sigset_t *set, int _sig) +static inline int __const_sigismember(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; return 1 & (set->sig[sig / _NSIG_BPW] >> (sig & ~(_NSIG_BPW-1))); } -extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) +static inline int __gen_sigismember(sigset_t *set, int _sig) { int ret; __asm__("btq %2,%1\n\tsbbq %0,%0" @@ -172,7 +172,7 @@ extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) __const_sigismember((set),(sig)) : \ __gen_sigismember((set),(sig))) -extern __inline__ int sigfindinword(unsigned long word) +static inline int sigfindinword(unsigned long word) { __asm__("bsfq %1,%0" : "=r"(word) : "rm"(word) : "cc"); return word; diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index de8b57b2b62..24e32611f0b 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -72,7 +72,7 @@ static inline int num_booting_cpus(void) #define raw_smp_processor_id() read_pda(cpunumber) -extern __inline int hard_smp_processor_id(void) +static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index 8606e170a7d..85348e02ad2 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -188,7 +188,7 @@ static inline void write_cr4(unsigned long val) #define __xg(x) ((volatile long *)(x)) -extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val) +static inline void set_64bit(volatile unsigned long *ptr, unsigned long val) { *ptr = val; } @@ -253,19 +253,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, case 2: __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 4: __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 8: __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; } diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h index 24ecf6a637c..f971f45d6d7 100644 --- a/include/asm-x86_64/timex.h +++ b/include/asm-x86_64/timex.h @@ -6,7 +6,6 @@ #ifndef _ASMx8664_TIMEX_H #define _ASMx8664_TIMEX_H -#include <linux/config.h> #include <asm/8253pit.h> #include <asm/msr.h> #include <asm/vsyscall.h> diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h index 505b0cf906d..4a9c20ea9b1 100644 --- a/include/asm-x86_64/tlbflush.h +++ b/include/asm-x86_64/tlbflush.h @@ -109,6 +109,10 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st #define TLBSTATE_OK 1 #define TLBSTATE_LAZY 2 +/* Roughly an IPI every 20MB with 4k pages for freeing page table + ranges. Cost is about 42k of memory for each CPU. */ +#define ARCH_FREE_PTE_NR 5350 + #endif #define flush_tlb_kernel_range(start, end) flush_tlb_all() diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index c1bc3fad482..1c603cd7e4d 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -13,7 +13,6 @@ extern cpumask_t cpu_online_map; extern unsigned char cpu_to_node[]; -extern unsigned char pci_bus_to_node[]; extern cpumask_t node_to_cpumask[]; #ifdef CONFIG_ACPI_NUMA @@ -26,7 +25,7 @@ extern int __node_distance(int, int); #define parent_node(node) (node) #define node_to_first_cpu(node) (__ffs(node_to_cpumask[node])) #define node_to_cpumask(node) (node_to_cpumask[node]) -#define pcibus_to_node(bus) pci_bus_to_node[(bus)->number] +#define pcibus_to_node(bus) ((long)(bus->sysdata)) #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)); /* sched_domains SD_NODE_INIT for x86_64 machines */ diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h index 2872da23fc7..438a3f52f83 100644 --- a/include/asm-x86_64/vsyscall.h +++ b/include/asm-x86_64/vsyscall.h @@ -29,7 +29,6 @@ enum vsyscall_num { struct vxtime_data { long hpet_address; /* HPET base address */ - unsigned long hz; /* HPET clocks / sec */ int last; unsigned long last_tsc; long quot; diff --git a/include/linux/crc16.h b/include/linux/crc16.h index bdedf825b04..9443c084f88 100644 --- a/include/linux/crc16.h +++ b/include/linux/crc16.h @@ -1,22 +1,11 @@ /* * crc16.h - CRC-16 routine * - * Implements the standard CRC-16, as used with 1-wire devices: + * Implements the standard CRC-16: * Width 16 * Poly 0x8005 (x^16 + x^15 + x^2 + 1) * Init 0 * - * For 1-wire devices, the CRC is stored inverted, LSB-first - * - * Example buffer with the CRC attached: - * 31 32 33 34 35 36 37 38 39 C2 44 - * - * The CRC over a buffer with the CRC attached is 0xB001. - * So, if (crc16(0, buf, size) == 0xB001) then the buffer is valid. - * - * Refer to "Application Note 937: Book of iButton Standards" for details. - * http://www.maxim-ic.com/appnotes.cfm/appnote_number/937 - * * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> * * This source code is licensed under the GNU General Public License, @@ -28,9 +17,6 @@ #include <linux/types.h> -#define CRC16_INIT 0 -#define CRC16_VALID 0xb001 - extern u16 const crc16_table[256]; extern u16 crc16(u16 crc, const u8 *buffer, size_t len); diff --git a/include/linux/dmi.h b/include/linux/dmi.h index c30175e8dec..a415f1d93e9 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -70,7 +70,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name, static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } static inline char * dmi_get_system_info(int field) { return NULL; } -static struct dmi_device * dmi_find_device(int type, const char *name, +static inline struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from) { return NULL; } #endif diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d99e7aeb7d3..0a90205184b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -57,6 +57,11 @@ extern void disable_irq(unsigned int irq); extern void enable_irq(unsigned int irq); #endif +#ifndef __ARCH_SET_SOFTIRQ_PENDING +#define set_softirq_pending(x) (local_softirq_pending() = (x)) +#define or_softirq_pending(x) (local_softirq_pending() |= (x)) +#endif + /* * Temporary defines for UP kernels, until all code gets fixed. */ @@ -123,7 +128,7 @@ struct softirq_action asmlinkage void do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); extern void softirq_init(void); -#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL << (nr); } while (0) +#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0) extern void FASTCALL(raise_softirq_irqoff(unsigned int nr)); extern void FASTCALL(raise_softirq(unsigned int nr)); diff --git a/include/linux/sched.h b/include/linux/sched.h index ed3bb19d133..38c8654aaa9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -785,7 +785,6 @@ struct task_struct { short il_next; #endif #ifdef CONFIG_CPUSETS - short cpuset_sem_nest_depth; struct cpuset *cpuset; nodemask_t mems_allowed; int cpuset_mems_generation; diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index fb57c221746..9facf733800 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -32,7 +32,6 @@ #define _LINUX_USBDEVICE_FS_H #include <linux/types.h> -#include <linux/compat.h> /* --------------------------------------------------------------------- */ @@ -125,6 +124,7 @@ struct usbdevfs_hub_portinfo { }; #ifdef CONFIG_COMPAT +#include <linux/compat.h> struct usbdevfs_urb32 { unsigned char type; unsigned char endpoint; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 407b5f0a8c8..79866bc6b3a 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -180,6 +180,8 @@ static struct super_block *cpuset_sb = NULL; */ static DECLARE_MUTEX(cpuset_sem); +static struct task_struct *cpuset_sem_owner; +static int cpuset_sem_depth; /* * The global cpuset semaphore cpuset_sem can be needed by the @@ -200,16 +202,19 @@ static DECLARE_MUTEX(cpuset_sem); static inline void cpuset_down(struct semaphore *psem) { - if (current->cpuset_sem_nest_depth == 0) + if (cpuset_sem_owner != current) { down(psem); - current->cpuset_sem_nest_depth++; + cpuset_sem_owner = current; + } + cpuset_sem_depth++; } static inline void cpuset_up(struct semaphore *psem) { - current->cpuset_sem_nest_depth--; - if (current->cpuset_sem_nest_depth == 0) + if (--cpuset_sem_depth == 0) { + cpuset_sem_owner = NULL; up(psem); + } } /* diff --git a/kernel/sched.c b/kernel/sched.c index e9ff04a9b56..81b3a96ed2d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3577,32 +3577,6 @@ task_t *idle_task(int cpu) } /** - * curr_task - return the current task for a given cpu. - * @cpu: the processor in question. - */ -task_t *curr_task(int cpu) -{ - return cpu_curr(cpu); -} - -/** - * set_curr_task - set the current task for a given cpu. - * @cpu: the processor in question. - * @p: the task pointer to set. - * - * Description: This function must only be used when non-maskable interrupts - * are serviced on a separate stack. It allows the architecture to switch the - * notion of the current task on a cpu in a non-blocking manner. This function - * must be called with interrupts disabled, the caller must save the original - * value of the current task (see curr_task() above) and restore that value - * before reenabling interrupts. - */ -void set_curr_task(int cpu, task_t *p) -{ - cpu_curr(cpu) = p; -} - -/** * find_process_by_pid - find a process with a matching PID value. * @pid: the pid in question. */ @@ -5628,3 +5602,47 @@ void normalize_rt_tasks(void) } #endif /* CONFIG_MAGIC_SYSRQ */ + +#ifdef CONFIG_IA64 +/* + * These functions are only useful for the IA64 MCA handling. + * + * They can only be called when the whole system has been + * stopped - every CPU needs to be quiescent, and no scheduling + * activity can take place. Using them for anything else would + * be a serious bug, and as a result, they aren't even visible + * under any other configuration. + */ + +/** + * curr_task - return the current task for a given cpu. + * @cpu: the processor in question. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + */ +task_t *curr_task(int cpu) +{ + return cpu_curr(cpu); +} + +/** + * set_curr_task - set the current task for a given cpu. + * @cpu: the processor in question. + * @p: the task pointer to set. + * + * Description: This function must only be used when non-maskable interrupts + * are serviced on a separate stack. It allows the architecture to switch the + * notion of the current task on a cpu in a non-blocking manner. This function + * must be called with all CPU's synchronized, and interrupts disabled, the + * and caller must save the original value of the current task (see + * curr_task() above) and restore that value before reenabling interrupts and + * re-starting the system. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + */ +void set_curr_task(int cpu, task_t *p) +{ + cpu_curr(cpu) = p; +} + +#endif diff --git a/kernel/softirq.c b/kernel/softirq.c index b4ab6af1dea..f766b2fc48b 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -84,7 +84,7 @@ asmlinkage void __do_softirq(void) cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ - local_softirq_pending() = 0; + set_softirq_pending(0); local_irq_enable(); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 3754c9a8f5c..016e89a44ac 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -170,11 +170,11 @@ config DEBUG_FS config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML) + depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML) default y if DEBUG_INFO && UML help If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. + and slower, but it might give very useful debugging information + on some architectures or you use external debuggers. + If you don't debug the kernel, you can say N. diff --git a/mm/bootmem.c b/mm/bootmem.c index c1330cc1978..8ec4e4c2a17 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -61,9 +61,17 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, { bootmem_data_t *bdata = pgdat->bdata; unsigned long mapsize = ((end - start)+7)/8; - - pgdat->pgdat_next = pgdat_list; - pgdat_list = pgdat; + static struct pglist_data *pgdat_last; + + pgdat->pgdat_next = NULL; + /* Add new nodes last so that bootmem always starts + searching in the first nodes, not the last ones */ + if (pgdat_last) + pgdat_last->pgdat_next = pgdat; + else { + pgdat_list = pgdat; + pgdat_last = pgdat; + } mapsize = ALIGN(mapsize, sizeof(long)); bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); diff --git a/mm/nommu.c b/mm/nommu.c index fd4e8df0f02..064d7044289 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -57,6 +57,11 @@ DECLARE_RWSEM(nommu_vma_sem); struct vm_operations_struct generic_file_vm_ops = { }; +EXPORT_SYMBOL(vmalloc); +EXPORT_SYMBOL(vfree); +EXPORT_SYMBOL(vmalloc_to_page); +EXPORT_SYMBOL(vmalloc_32); + /* * Handle all mappings that got truncated by a "truncate()" * system call. @@ -142,6 +147,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, return(i); } +EXPORT_SYMBOL(get_user_pages); + DEFINE_RWLOCK(vmlist_lock); struct vm_struct *vmlist; @@ -852,7 +859,7 @@ unsigned long do_mmap_pgoff(struct file *file, error_getting_vma: up_write(&nommu_vma_sem); kfree(vml); - printk("Allocation of vml for %lu byte allocation from process %d failed\n", + printk("Allocation of vma for %lu byte allocation from process %d failed\n", len, current->pid); show_free_areas(); return -ENOMEM; @@ -909,7 +916,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) if ((*parent)->vma->vm_start == addr && - (*parent)->vma->vm_end == end) + ((len == 0) || ((*parent)->vma->vm_end == end))) goto found; printk("munmap of non-mmaped memory by process %d (%s): %p\n", @@ -1054,7 +1061,8 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot) { - return -EPERM; + vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; + return 0; } void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) @@ -1073,9 +1081,10 @@ void arch_unmap_area(struct mm_struct *mm, unsigned long addr) void update_mem_hiwater(struct task_struct *tsk) { - unsigned long rss = get_mm_counter(tsk->mm, rss); + unsigned long rss; if (likely(tsk->mm)) { + rss = get_mm_counter(tsk->mm, rss); if (tsk->mm->hiwater_rss < rss) tsk->mm->hiwater_rss = rss; if (tsk->mm->hiwater_vm < tsk->mm->total_vm) |