diff --git a/[refs] b/[refs] index 70156c49f63f..812d145932c9 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 4b37ba90f49d4157ac5628f8d730d3505f176724 +refs/heads/master: f253b86b4ad1b3220544e75880510fd455ebd23f diff --git a/trunk/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra b/trunk/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra deleted file mode 100644 index ad1125b02ff4..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra +++ /dev/null @@ -1,98 +0,0 @@ -What: /sys/bus/usb/devices/-:./actual_cpi -Date: August 2010 -Contact: Stefan Achatz -Description: It is possible to switch the cpi setting of the mouse with the - press of a button. - When read, this file returns the raw number of the actual cpi - setting reported by the mouse. This number has to be further - processed to receive the real dpi value. - - VALUE DPI - 1 400 - 2 800 - 4 1600 - - This file is readonly. - -What: /sys/bus/usb/devices/-:./actual_profile -Date: August 2010 -Contact: Stefan Achatz -Description: When read, this file returns the number of the actual profile in - range 0-4. - This file is readonly. - -What: /sys/bus/usb/devices/-:./firmware_version -Date: August 2010 -Contact: Stefan Achatz -Description: When read, this file returns the raw integer version number of the - firmware reported by the mouse. Using the integer value eases - further usage in other programs. To receive the real version - number the decimal point has to be shifted 2 positions to the - left. E.g. a returned value of 138 means 1.38 - This file is readonly. - -What: /sys/bus/usb/devices/-:./profile_settings -Date: August 2010 -Contact: Stefan Achatz -Description: The mouse can store 5 profiles which can be switched by the - press of a button. A profile is split in settings and buttons. - profile_settings holds informations like resolution, sensitivity - and light effects. - When written, this file lets one write the respective profile - settings back to the mouse. The data has to be 13 bytes long. - The mouse will reject invalid data. - Which profile to write is determined by the profile number - contained in the data. - This file is writeonly. - -What: /sys/bus/usb/devices/-:./profile[1-5]_settings -Date: August 2010 -Contact: Stefan Achatz -Description: The mouse can store 5 profiles which can be switched by the - press of a button. A profile is split in settings and buttons. - profile_settings holds informations like resolution, sensitivity - and light effects. - When read, these files return the respective profile settings. - The returned data is 13 bytes in size. - This file is readonly. - -What: /sys/bus/usb/devices/-:./profile_buttons -Date: August 2010 -Contact: Stefan Achatz -Description: The mouse can store 5 profiles which can be switched by the - press of a button. A profile is split in settings and buttons. - profile_buttons holds informations about button layout. - When written, this file lets one write the respective profile - buttons back to the mouse. The data has to be 19 bytes long. - The mouse will reject invalid data. - Which profile to write is determined by the profile number - contained in the data. - This file is writeonly. - -What: /sys/bus/usb/devices/-:./profile[1-5]_buttons -Date: August 2010 -Contact: Stefan Achatz -Description: The mouse can store 5 profiles which can be switched by the - press of a button. A profile is split in settings and buttons. - profile_buttons holds informations about button layout. - When read, these files return the respective profile buttons. - The returned data is 19 bytes in size. - This file is readonly. - -What: /sys/bus/usb/devices/-:./startup_profile -Date: August 2010 -Contact: Stefan Achatz -Description: The integer value of this attribute ranges from 0-4. - When read, this attribute returns the number of the profile - that's active when the mouse is powered on. - This file is readonly. - -What: /sys/bus/usb/devices/-:./settings -Date: August 2010 -Contact: Stefan Achatz -Description: When read, this file returns the settings stored in the mouse. - The size of the data is 3 bytes and holds information on the - startup_profile. - When written, this file lets write settings back to the mouse. - The data has to be 3 bytes long. The mouse will reject invalid - data. diff --git a/trunk/Documentation/arm/SA1100/FreeBird b/trunk/Documentation/arm/SA1100/FreeBird index ab9193663b2b..fb23b770aaf4 100644 --- a/trunk/Documentation/arm/SA1100/FreeBird +++ b/trunk/Documentation/arm/SA1100/FreeBird @@ -1,6 +1,6 @@ -Freebird-1.1 is produced by Legend(C), Inc. +Freebird-1.1 is produced by Legned(C) ,Inc. http://web.archive.org/web/*/http://www.legend.com.cn -and software/linux maintained by Coventive(C), Inc. +and software/linux mainatined by Coventive(C),Inc. (http://www.coventive.com) Based on the Nicolas's strongarm kernel tree. diff --git a/trunk/Documentation/input/ntrig.txt b/trunk/Documentation/input/ntrig.txt deleted file mode 100644 index be1fd981f73f..000000000000 --- a/trunk/Documentation/input/ntrig.txt +++ /dev/null @@ -1,126 +0,0 @@ -N-Trig touchscreen Driver -------------------------- - Copyright (c) 2008-2010 Rafi Rubin - Copyright (c) 2009-2010 Stephane Chatty - -This driver provides support for N-Trig pen and multi-touch sensors. Single -and multi-touch events are translated to the appropriate protocols for -the hid and input systems. Pen events are sufficiently hid compliant and -are left to the hid core. The driver also provides additional filtering -and utility functions accessible with sysfs and module parameters. - -This driver has been reported to work properly with multiple N-Trig devices -attached. - - -Parameters ----------- - -Note: values set at load time are global and will apply to all applicable -devices. Adjusting parameters with sysfs will override the load time values, -but only for that one device. - -The following parameters are used to configure filters to reduce noise: - -activate_slack number of fingers to ignore before processing events - -activation_height size threshold to activate immediately -activation_width - -min_height size threshold bellow which fingers are ignored -min_width both to decide activation and during activity - -deactivate_slack the number of "no contact" frames to ignore before - propagating the end of activity events - -When the last finger is removed from the device, it sends a number of empty -frames. By holding off on deactivation for a few frames we can tolerate false -erroneous disconnects, where the sensor may mistakenly not detect a finger that -is still present. Thus deactivate_slack addresses problems where a users might -see breaks in lines during drawing, or drop an object during a long drag. - - -Additional sysfs items ----------------------- - -These nodes just provide easy access to the ranges reported by the device. -sensor_logical_height the range for positions reported during activity -sensor_logical_width - -sensor_physical_height internal ranges not used for normal events but -sensor_physical_width useful for tuning - -All N-Trig devices with product id of 1 report events in the ranges of -X: 0-9600 -Y: 0-7200 -However not all of these devices have the same physical dimensions. Most -seem to be 12" sensors (Dell Latitude XT and XT2 and the HP TX2), and -at least one model (Dell Studio 17) has a 17" sensor. The ratio of physical -to logical sizes is used to adjust the size based filter parameters. - - -Filtering ---------- - -With the release of the early multi-touch firmwares it became increasingly -obvious that these sensors were prone to erroneous events. Users reported -seeing both inappropriately dropped contact and ghosts, contacts reported -where no finger was actually touching the screen. - -Deactivation slack helps prevent dropped contact for single touch use, but does -not address the problem of dropping one of more contacts while other contacts -are still active. Drops in the multi-touch context require additional -processing and should be handled in tandem with tacking. - -As observed ghost contacts are similar to actual use of the sensor, but they -seem to have different profiles. Ghost activity typically shows up as small -short lived touches. As such, I assume that the longer the continuous stream -of events the more likely those events are from a real contact, and that the -larger the size of each contact the more likely it is real. Balancing the -goals of preventing ghosts and accepting real events quickly (to minimize -user observable latency), the filter accumulates confidence for incoming -events until it hits thresholds and begins propagating. In the interest in -minimizing stored state as well as the cost of operations to make a decision, -I've kept that decision simple. - -Time is measured in terms of the number of fingers reported, not frames since -the probability of multiple simultaneous ghosts is expected to drop off -dramatically with increasing numbers. Rather than accumulate weight as a -function of size, I just use it as a binary threshold. A sufficiently large -contact immediately overrides the waiting period and leads to activation. - -Setting the activation size thresholds to large values will result in deciding -primarily on activation slack. If you see longer lived ghosts, turning up the -activation slack while reducing the size thresholds may suffice to eliminate -the ghosts while keeping the screen quite responsive to firm taps. - -Contacts continue to be filtered with min_height and min_width even after -the initial activation filter is satisfied. The intent is to provide -a mechanism for filtering out ghosts in the form of an extra finger while -you actually are using the screen. In practice this sort of ghost has -been far less problematic or relatively rare and I've left the defaults -set to 0 for both parameters, effectively turning off that filter. - -I don't know what the optimal values are for these filters. If the defaults -don't work for you, please play with the parameters. If you do find other -values more comfortable, I would appreciate feedback. - -The calibration of these devices does drift over time. If ghosts or contact -dropping worsen and interfere with the normal usage of your device, try -recalibrating it. - - -Calibration ------------ - -The N-Trig windows tools provide calibration and testing routines. Also an -unofficial unsupported set of user space tools including a calibrator is -available at: -http://code.launchpad.net/~rafi-seas/+junk/ntrig_calib - - -Tracking --------- - -As of yet, all tested N-Trig firmwares do not track fingers. When multiple -contacts are active they seem to be sorted primarily by Y position. diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 0b6815504e6d..4cd8b86e00ea 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1131,12 +1131,8 @@ and is between 256 and 4096 characters. It is defined in the file kvm.oos_shadow= [KVM] Disable out-of-sync shadow paging. Default is 1 (enabled) - kvm.mmu_audit= [KVM] This is a R/W parameter which allows audit - KVM MMU at runtime. - Default is 0 (off) - kvm-amd.nested= [KVM,AMD] Allow nested virtualization in KVM/SVM. - Default is 1 (enabled) + Default is 0 (off) kvm-amd.npt= [KVM,AMD] Disable nested paging (virtualized MMU) for all guests. @@ -1702,8 +1698,6 @@ and is between 256 and 4096 characters. It is defined in the file nojitter [IA64] Disables jitter checking for ITC timers. - no-kvmclock [X86,KVM] Disable paravirtualized KVM clock driver - nolapic [X86-32,APIC] Do not enable or use the local APIC. nolapic_timer [X86-32,APIC] Do not use the local APIC timer. @@ -1724,7 +1718,7 @@ and is between 256 and 4096 characters. It is defined in the file norandmaps Don't use address space randomization. Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space - noreplace-paravirt [X86,IA-64,PV_OPS] Don't patch paravirt_ops + noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops noreplace-smp [X86-32,SMP] Don't replace SMP instructions with UP alternatives diff --git a/trunk/Documentation/kvm/api.txt b/trunk/Documentation/kvm/api.txt index b336266bea5e..5f5b64982b1a 100644 --- a/trunk/Documentation/kvm/api.txt +++ b/trunk/Documentation/kvm/api.txt @@ -320,13 +320,13 @@ struct kvm_translation { 4.15 KVM_INTERRUPT Capability: basic -Architectures: x86, ppc +Architectures: x86 Type: vcpu ioctl Parameters: struct kvm_interrupt (in) Returns: 0 on success, -1 on error Queues a hardware interrupt vector to be injected. This is only -useful if in-kernel local APIC or equivalent is not used. +useful if in-kernel local APIC is not used. /* for KVM_INTERRUPT */ struct kvm_interrupt { @@ -334,37 +334,8 @@ struct kvm_interrupt { __u32 irq; }; -X86: - Note 'irq' is an interrupt vector, not an interrupt pin or line. -PPC: - -Queues an external interrupt to be injected. This ioctl is overleaded -with 3 different irq values: - -a) KVM_INTERRUPT_SET - - This injects an edge type external interrupt into the guest once it's ready - to receive interrupts. When injected, the interrupt is done. - -b) KVM_INTERRUPT_UNSET - - This unsets any pending interrupt. - - Only available with KVM_CAP_PPC_UNSET_IRQ. - -c) KVM_INTERRUPT_SET_LEVEL - - This injects a level type external interrupt into the guest context. The - interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET - is triggered. - - Only available with KVM_CAP_PPC_IRQ_LEVEL. - -Note that any value for 'irq' other than the ones stated above is invalid -and incurs unexpected behavior. - 4.16 KVM_DEBUG_GUEST Capability: basic @@ -1042,9 +1013,8 @@ number is just right, the 'nent' field is adjusted to the number of valid entries in the 'entries' array, which is then filled. The entries returned are the host cpuid as returned by the cpuid instruction, -with unknown or unsupported features masked out. Some features (for example, -x2apic), may not be present in the host cpu, but are exposed by kvm if it can -emulate them efficiently. The fields in each entry are defined as follows: +with unknown or unsupported features masked out. The fields in each entry +are defined as follows: function: the eax value used to obtain the entry index: the ecx value used to obtain the entry (for entries that are @@ -1062,29 +1032,6 @@ emulate them efficiently. The fields in each entry are defined as follows: eax, ebx, ecx, edx: the values returned by the cpuid instruction for this function/index combination -4.46 KVM_PPC_GET_PVINFO - -Capability: KVM_CAP_PPC_GET_PVINFO -Architectures: ppc -Type: vm ioctl -Parameters: struct kvm_ppc_pvinfo (out) -Returns: 0 on success, !0 on error - -struct kvm_ppc_pvinfo { - __u32 flags; - __u32 hcall[4]; - __u8 pad[108]; -}; - -This ioctl fetches PV specific information that need to be passed to the guest -using the device tree or other means from vm context. - -For now the only implemented piece of information distributed here is an array -of 4 instructions that make up a hypercall. - -If any additional field gets added to this structure later on, a bit for that -additional piece of information will be set in the flags bitmap. - 5. The kvm_run structure Application code obtains a pointer to the kvm_run structure by diff --git a/trunk/Documentation/kvm/ppc-pv.txt b/trunk/Documentation/kvm/ppc-pv.txt deleted file mode 100644 index a7f2244b3be9..000000000000 --- a/trunk/Documentation/kvm/ppc-pv.txt +++ /dev/null @@ -1,196 +0,0 @@ -The PPC KVM paravirtual interface -================================= - -The basic execution principle by which KVM on PowerPC works is to run all kernel -space code in PR=1 which is user space. This way we trap all privileged -instructions and can emulate them accordingly. - -Unfortunately that is also the downfall. There are quite some privileged -instructions that needlessly return us to the hypervisor even though they -could be handled differently. - -This is what the PPC PV interface helps with. It takes privileged instructions -and transforms them into unprivileged ones with some help from the hypervisor. -This cuts down virtualization costs by about 50% on some of my benchmarks. - -The code for that interface can be found in arch/powerpc/kernel/kvm* - -Querying for existence -====================== - -To find out if we're running on KVM or not, we leverage the device tree. When -Linux is running on KVM, a node /hypervisor exists. That node contains a -compatible property with the value "linux,kvm". - -Once you determined you're running under a PV capable KVM, you can now use -hypercalls as described below. - -KVM hypercalls -============== - -Inside the device tree's /hypervisor node there's a property called -'hypercall-instructions'. This property contains at most 4 opcodes that make -up the hypercall. To call a hypercall, just call these instructions. - -The parameters are as follows: - - Register IN OUT - - r0 - volatile - r3 1st parameter Return code - r4 2nd parameter 1st output value - r5 3rd parameter 2nd output value - r6 4th parameter 3rd output value - r7 5th parameter 4th output value - r8 6th parameter 5th output value - r9 7th parameter 6th output value - r10 8th parameter 7th output value - r11 hypercall number 8th output value - r12 - volatile - -Hypercall definitions are shared in generic code, so the same hypercall numbers -apply for x86 and powerpc alike with the exception that each KVM hypercall -also needs to be ORed with the KVM vendor code which is (42 << 16). - -Return codes can be as follows: - - Code Meaning - - 0 Success - 12 Hypercall not implemented - <0 Error - -The magic page -============== - -To enable communication between the hypervisor and guest there is a new shared -page that contains parts of supervisor visible register state. The guest can -map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE. - -With this hypercall issued the guest always gets the magic page mapped at the -desired location in effective and physical address space. For now, we always -map the page to -4096. This way we can access it using absolute load and store -functions. The following instruction reads the first field of the magic page: - - ld rX, -4096(0) - -The interface is designed to be extensible should there be need later to add -additional registers to the magic page. If you add fields to the magic page, -also define a new hypercall feature to indicate that the host can give you more -registers. Only if the host supports the additional features, make use of them. - -The magic page has the following layout as described in -arch/powerpc/include/asm/kvm_para.h: - -struct kvm_vcpu_arch_shared { - __u64 scratch1; - __u64 scratch2; - __u64 scratch3; - __u64 critical; /* Guest may not get interrupts if == r1 */ - __u64 sprg0; - __u64 sprg1; - __u64 sprg2; - __u64 sprg3; - __u64 srr0; - __u64 srr1; - __u64 dar; - __u64 msr; - __u32 dsisr; - __u32 int_pending; /* Tells the guest if we have an interrupt */ -}; - -Additions to the page must only occur at the end. Struct fields are always 32 -or 64 bit aligned, depending on them being 32 or 64 bit wide respectively. - -Magic page features -=================== - -When mapping the magic page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE, -a second return value is passed to the guest. This second return value contains -a bitmap of available features inside the magic page. - -The following enhancements to the magic page are currently available: - - KVM_MAGIC_FEAT_SR Maps SR registers r/w in the magic page - -For enhanced features in the magic page, please check for the existence of the -feature before using them! - -MSR bits -======== - -The MSR contains bits that require hypervisor intervention and bits that do -not require direct hypervisor intervention because they only get interpreted -when entering the guest or don't have any impact on the hypervisor's behavior. - -The following bits are safe to be set inside the guest: - - MSR_EE - MSR_RI - MSR_CR - MSR_ME - -If any other bit changes in the MSR, please still use mtmsr(d). - -Patched instructions -==================== - -The "ld" and "std" instructions are transormed to "lwz" and "stw" instructions -respectively on 32 bit systems with an added offset of 4 to accomodate for big -endianness. - -The following is a list of mapping the Linux kernel performs when running as -guest. Implementing any of those mappings is optional, as the instruction traps -also act on the shared page. So calling privileged instructions still works as -before. - -From To -==== == - -mfmsr rX ld rX, magic_page->msr -mfsprg rX, 0 ld rX, magic_page->sprg0 -mfsprg rX, 1 ld rX, magic_page->sprg1 -mfsprg rX, 2 ld rX, magic_page->sprg2 -mfsprg rX, 3 ld rX, magic_page->sprg3 -mfsrr0 rX ld rX, magic_page->srr0 -mfsrr1 rX ld rX, magic_page->srr1 -mfdar rX ld rX, magic_page->dar -mfdsisr rX lwz rX, magic_page->dsisr - -mtmsr rX std rX, magic_page->msr -mtsprg 0, rX std rX, magic_page->sprg0 -mtsprg 1, rX std rX, magic_page->sprg1 -mtsprg 2, rX std rX, magic_page->sprg2 -mtsprg 3, rX std rX, magic_page->sprg3 -mtsrr0 rX std rX, magic_page->srr0 -mtsrr1 rX std rX, magic_page->srr1 -mtdar rX std rX, magic_page->dar -mtdsisr rX stw rX, magic_page->dsisr - -tlbsync nop - -mtmsrd rX, 0 b -mtmsr rX b - -mtmsrd rX, 1 b - -[Book3S only] -mtsrin rX, rY b - -[BookE only] -wrteei [0|1] b - - -Some instructions require more logic to determine what's going on than a load -or store instruction can deliver. To enable patching of those, we keep some -RAM around where we can live translate instructions to. What happens is the -following: - - 1) copy emulation code to memory - 2) patch that code to fit the emulated instruction - 3) patch that code to return to the original pc + 4 - 4) patch the original instruction to branch to the new code - -That way we can inject an arbitrary amount of code as replacement for a single -instruction. This allows us to check for pending interrupts when setting EE=1 -for example. diff --git a/trunk/Documentation/kvm/timekeeping.txt b/trunk/Documentation/kvm/timekeeping.txt deleted file mode 100644 index 0c5033a58c9e..000000000000 --- a/trunk/Documentation/kvm/timekeeping.txt +++ /dev/null @@ -1,612 +0,0 @@ - - Timekeeping Virtualization for X86-Based Architectures - - Zachary Amsden - Copyright (c) 2010, Red Hat. All rights reserved. - -1) Overview -2) Timing Devices -3) TSC Hardware -4) Virtualization Problems - -========================================================================= - -1) Overview - -One of the most complicated parts of the X86 platform, and specifically, -the virtualization of this platform is the plethora of timing devices available -and the complexity of emulating those devices. In addition, virtualization of -time introduces a new set of challenges because it introduces a multiplexed -division of time beyond the control of the guest CPU. - -First, we will describe the various timekeeping hardware available, then -present some of the problems which arise and solutions available, giving -specific recommendations for certain classes of KVM guests. - -The purpose of this document is to collect data and information relevant to -timekeeping which may be difficult to find elsewhere, specifically, -information relevant to KVM and hardware-based virtualization. - -========================================================================= - -2) Timing Devices - -First we discuss the basic hardware devices available. TSC and the related -KVM clock are special enough to warrant a full exposition and are described in -the following section. - -2.1) i8254 - PIT - -One of the first timer devices available is the programmable interrupt timer, -or PIT. The PIT has a fixed frequency 1.193182 MHz base clock and three -channels which can be programmed to deliver periodic or one-shot interrupts. -These three channels can be configured in different modes and have individual -counters. Channel 1 and 2 were not available for general use in the original -IBM PC, and historically were connected to control RAM refresh and the PC -speaker. Now the PIT is typically integrated as part of an emulated chipset -and a separate physical PIT is not used. - -The PIT uses I/O ports 0x40 - 0x43. Access to the 16-bit counters is done -using single or multiple byte access to the I/O ports. There are 6 modes -available, but not all modes are available to all timers, as only timer 2 -has a connected gate input, required for modes 1 and 5. The gate line is -controlled by port 61h, bit 0, as illustrated in the following diagram. - - -------------- ---------------- -| | | | -| 1.1932 MHz |---------->| CLOCK OUT | ---------> IRQ 0 -| Clock | | | | - -------------- | +->| GATE TIMER 0 | - | ---------------- - | - | ---------------- - | | | - |------>| CLOCK OUT | ---------> 66.3 KHZ DRAM - | | | (aka /dev/null) - | +->| GATE TIMER 1 | - | ---------------- - | - | ---------------- - | | | - |------>| CLOCK OUT | ---------> Port 61h, bit 5 - | | | -Port 61h, bit 0 ---------->| GATE TIMER 2 | \_.---- ____ - ---------------- _| )--|LPF|---Speaker - / *---- \___/ -Port 61h, bit 1 -----------------------------------/ - -The timer modes are now described. - -Mode 0: Single Timeout. This is a one-shot software timeout that counts down - when the gate is high (always true for timers 0 and 1). When the count - reaches zero, the output goes high. - -Mode 1: Triggered One-shot. The output is intially set high. When the gate - line is set high, a countdown is initiated (which does not stop if the gate is - lowered), during which the output is set low. When the count reaches zero, - the output goes high. - -Mode 2: Rate Generator. The output is initially set high. When the countdown - reaches 1, the output goes low for one count and then returns high. The value - is reloaded and the countdown automatically resumes. If the gate line goes - low, the count is halted. If the output is low when the gate is lowered, the - output automatically goes high (this only affects timer 2). - -Mode 3: Square Wave. This generates a high / low square wave. The count - determines the length of the pulse, which alternates between high and low - when zero is reached. The count only proceeds when gate is high and is - automatically reloaded on reaching zero. The count is decremented twice at - each clock to generate a full high / low cycle at the full periodic rate. - If the count is even, the clock remains high for N/2 counts and low for N/2 - counts; if the clock is odd, the clock is high for (N+1)/2 counts and low - for (N-1)/2 counts. Only even values are latched by the counter, so odd - values are not observed when reading. This is the intended mode for timer 2, - which generates sine-like tones by low-pass filtering the square wave output. - -Mode 4: Software Strobe. After programming this mode and loading the counter, - the output remains high until the counter reaches zero. Then the output - goes low for 1 clock cycle and returns high. The counter is not reloaded. - Counting only occurs when gate is high. - -Mode 5: Hardware Strobe. After programming and loading the counter, the - output remains high. When the gate is raised, a countdown is initiated - (which does not stop if the gate is lowered). When the counter reaches zero, - the output goes low for 1 clock cycle and then returns high. The counter is - not reloaded. - -In addition to normal binary counting, the PIT supports BCD counting. The -command port, 0x43 is used to set the counter and mode for each of the three -timers. - -PIT commands, issued to port 0x43, using the following bit encoding: - -Bit 7-4: Command (See table below) -Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined) -Bit 0 : Binary (0) / BCD (1) - -Command table: - -0000 - Latch Timer 0 count for port 0x40 - sample and hold the count to be read in port 0x40; - additional commands ignored until counter is read; - mode bits ignored. - -0001 - Set Timer 0 LSB mode for port 0x40 - set timer to read LSB only and force MSB to zero; - mode bits set timer mode - -0010 - Set Timer 0 MSB mode for port 0x40 - set timer to read MSB only and force LSB to zero; - mode bits set timer mode - -0011 - Set Timer 0 16-bit mode for port 0x40 - set timer to read / write LSB first, then MSB; - mode bits set timer mode - -0100 - Latch Timer 1 count for port 0x41 - as described above -0101 - Set Timer 1 LSB mode for port 0x41 - as described above -0110 - Set Timer 1 MSB mode for port 0x41 - as described above -0111 - Set Timer 1 16-bit mode for port 0x41 - as described above - -1000 - Latch Timer 2 count for port 0x42 - as described above -1001 - Set Timer 2 LSB mode for port 0x42 - as described above -1010 - Set Timer 2 MSB mode for port 0x42 - as described above -1011 - Set Timer 2 16-bit mode for port 0x42 as described above - -1101 - General counter latch - Latch combination of counters into corresponding ports - Bit 3 = Counter 2 - Bit 2 = Counter 1 - Bit 1 = Counter 0 - Bit 0 = Unused - -1110 - Latch timer status - Latch combination of counter mode into corresponding ports - Bit 3 = Counter 2 - Bit 2 = Counter 1 - Bit 1 = Counter 0 - - The output of ports 0x40-0x42 following this command will be: - - Bit 7 = Output pin - Bit 6 = Count loaded (0 if timer has expired) - Bit 5-4 = Read / Write mode - 01 = MSB only - 10 = LSB only - 11 = LSB / MSB (16-bit) - Bit 3-1 = Mode - Bit 0 = Binary (0) / BCD mode (1) - -2.2) RTC - -The second device which was available in the original PC was the MC146818 real -time clock. The original device is now obsolete, and usually emulated by the -system chipset, sometimes by an HPET and some frankenstein IRQ routing. - -The RTC is accessed through CMOS variables, which uses an index register to -control which bytes are read. Since there is only one index register, read -of the CMOS and read of the RTC require lock protection (in addition, it is -dangerous to allow userspace utilities such as hwclock to have direct RTC -access, as they could corrupt kernel reads and writes of CMOS memory). - -The RTC generates an interrupt which is usually routed to IRQ 8. The interrupt -can function as a periodic timer, an additional once a day alarm, and can issue -interrupts after an update of the CMOS registers by the MC146818 is complete. -The type of interrupt is signalled in the RTC status registers. - -The RTC will update the current time fields by battery power even while the -system is off. The current time fields should not be read while an update is -in progress, as indicated in the status register. - -The clock uses a 32.768kHz crystal, so bits 6-4 of register A should be -programmed to a 32kHz divider if the RTC is to count seconds. - -This is the RAM map originally used for the RTC/CMOS: - -Location Size Description ------------------------------------------- -00h byte Current second (BCD) -01h byte Seconds alarm (BCD) -02h byte Current minute (BCD) -03h byte Minutes alarm (BCD) -04h byte Current hour (BCD) -05h byte Hours alarm (BCD) -06h byte Current day of week (BCD) -07h byte Current day of month (BCD) -08h byte Current month (BCD) -09h byte Current year (BCD) -0Ah byte Register A - bit 7 = Update in progress - bit 6-4 = Divider for clock - 000 = 4.194 MHz - 001 = 1.049 MHz - 010 = 32 kHz - 10X = test modes - 110 = reset / disable - 111 = reset / disable - bit 3-0 = Rate selection for periodic interrupt - 000 = periodic timer disabled - 001 = 3.90625 uS - 010 = 7.8125 uS - 011 = .122070 mS - 100 = .244141 mS - ... - 1101 = 125 mS - 1110 = 250 mS - 1111 = 500 mS -0Bh byte Register B - bit 7 = Run (0) / Halt (1) - bit 6 = Periodic interrupt enable - bit 5 = Alarm interrupt enable - bit 4 = Update-ended interrupt enable - bit 3 = Square wave interrupt enable - bit 2 = BCD calendar (0) / Binary (1) - bit 1 = 12-hour mode (0) / 24-hour mode (1) - bit 0 = 0 (DST off) / 1 (DST enabled) -OCh byte Register C (read only) - bit 7 = interrupt request flag (IRQF) - bit 6 = periodic interrupt flag (PF) - bit 5 = alarm interrupt flag (AF) - bit 4 = update interrupt flag (UF) - bit 3-0 = reserved -ODh byte Register D (read only) - bit 7 = RTC has power - bit 6-0 = reserved -32h byte Current century BCD (*) - (*) location vendor specific and now determined from ACPI global tables - -2.3) APIC - -On Pentium and later processors, an on-board timer is available to each CPU -as part of the Advanced Programmable Interrupt Controller. The APIC is -accessed through memory-mapped registers and provides interrupt service to each -CPU, used for IPIs and local timer interrupts. - -Although in theory the APIC is a safe and stable source for local interrupts, -in practice, many bugs and glitches have occurred due to the special nature of -the APIC CPU-local memory-mapped hardware. Beware that CPU errata may affect -the use of the APIC and that workarounds may be required. In addition, some of -these workarounds pose unique constraints for virtualization - requiring either -extra overhead incurred from extra reads of memory-mapped I/O or additional -functionality that may be more computationally expensive to implement. - -Since the APIC is documented quite well in the Intel and AMD manuals, we will -avoid repetition of the detail here. It should be pointed out that the APIC -timer is programmed through the LVT (local vector timer) register, is capable -of one-shot or periodic operation, and is based on the bus clock divided down -by the programmable divider register. - -2.4) HPET - -HPET is quite complex, and was originally intended to replace the PIT / RTC -support of the X86 PC. It remains to be seen whether that will be the case, as -the de facto standard of PC hardware is to emulate these older devices. Some -systems designated as legacy free may support only the HPET as a hardware timer -device. - -The HPET spec is rather loose and vague, requiring at least 3 hardware timers, -but allowing implementation freedom to support many more. It also imposes no -fixed rate on the timer frequency, but does impose some extremal values on -frequency, error and slew. - -In general, the HPET is recommended as a high precision (compared to PIT /RTC) -time source which is independent of local variation (as there is only one HPET -in any given system). The HPET is also memory-mapped, and its presence is -indicated through ACPI tables by the BIOS. - -Detailed specification of the HPET is beyond the current scope of this -document, as it is also very well documented elsewhere. - -2.5) Offboard Timers - -Several cards, both proprietary (watchdog boards) and commonplace (e1000) have -timing chips built into the cards which may have registers which are accessible -to kernel or user drivers. To the author's knowledge, using these to generate -a clocksource for a Linux or other kernel has not yet been attempted and is in -general frowned upon as not playing by the agreed rules of the game. Such a -timer device would require additional support to be virtualized properly and is -not considered important at this time as no known operating system does this. - -========================================================================= - -3) TSC Hardware - -The TSC or time stamp counter is relatively simple in theory; it counts -instruction cycles issued by the processor, which can be used as a measure of -time. In practice, due to a number of problems, it is the most complicated -timekeeping device to use. - -The TSC is represented internally as a 64-bit MSR which can be read with the -RDMSR, RDTSC, or RDTSCP (when available) instructions. In the past, hardware -limitations made it possible to write the TSC, but generally on old hardware it -was only possible to write the low 32-bits of the 64-bit counter, and the upper -32-bits of the counter were cleared. Now, however, on Intel processors family -0Fh, for models 3, 4 and 6, and family 06h, models e and f, this restriction -has been lifted and all 64-bits are writable. On AMD systems, the ability to -write the TSC MSR is not an architectural guarantee. - -The TSC is accessible from CPL-0 and conditionally, for CPL > 0 software by -means of the CR4.TSD bit, which when enabled, disables CPL > 0 TSC access. - -Some vendors have implemented an additional instruction, RDTSCP, which returns -atomically not just the TSC, but an indicator which corresponds to the -processor number. This can be used to index into an array of TSC variables to -determine offset information in SMP systems where TSCs are not synchronized. -The presence of this instruction must be determined by consulting CPUID feature -bits. - -Both VMX and SVM provide extension fields in the virtualization hardware which -allows the guest visible TSC to be offset by a constant. Newer implementations -promise to allow the TSC to additionally be scaled, but this hardware is not -yet widely available. - -3.1) TSC synchronization - -The TSC is a CPU-local clock in most implementations. This means, on SMP -platforms, the TSCs of different CPUs may start at different times depending -on when the CPUs are powered on. Generally, CPUs on the same die will share -the same clock, however, this is not always the case. - -The BIOS may attempt to resynchronize the TSCs during the poweron process and -the operating system or other system software may attempt to do this as well. -Several hardware limitations make the problem worse - if it is not possible to -write the full 64-bits of the TSC, it may be impossible to match the TSC in -newly arriving CPUs to that of the rest of the system, resulting in -unsynchronized TSCs. This may be done by BIOS or system software, but in -practice, getting a perfectly synchronized TSC will not be possible unless all -values are read from the same clock, which generally only is possible on single -socket systems or those with special hardware support. - -3.2) TSC and CPU hotplug - -As touched on already, CPUs which arrive later than the boot time of the system -may not have a TSC value that is synchronized with the rest of the system. -Either system software, BIOS, or SMM code may actually try to establish the TSC -to a value matching the rest of the system, but a perfect match is usually not -a guarantee. This can have the effect of bringing a system from a state where -TSC is synchronized back to a state where TSC synchronization flaws, however -small, may be exposed to the OS and any virtualization environment. - -3.3) TSC and multi-socket / NUMA - -Multi-socket systems, especially large multi-socket systems are likely to have -individual clocksources rather than a single, universally distributed clock. -Since these clocks are driven by different crystals, they will not have -perfectly matched frequency, and temperature and electrical variations will -cause the CPU clocks, and thus the TSCs to drift over time. Depending on the -exact clock and bus design, the drift may or may not be fixed in absolute -error, and may accumulate over time. - -In addition, very large systems may deliberately slew the clocks of individual -cores. This technique, known as spread-spectrum clocking, reduces EMI at the -clock frequency and harmonics of it, which may be required to pass FCC -standards for telecommunications and computer equipment. - -It is recommended not to trust the TSCs to remain synchronized on NUMA or -multiple socket systems for these reasons. - -3.4) TSC and C-states - -C-states, or idling states of the processor, especially C1E and deeper sleep -states may be problematic for TSC as well. The TSC may stop advancing in such -a state, resulting in a TSC which is behind that of other CPUs when execution -is resumed. Such CPUs must be detected and flagged by the operating system -based on CPU and chipset identifications. - -The TSC in such a case may be corrected by catching it up to a known external -clocksource. - -3.5) TSC frequency change / P-states - -To make things slightly more interesting, some CPUs may change frequency. They -may or may not run the TSC at the same rate, and because the frequency change -may be staggered or slewed, at some points in time, the TSC rate may not be -known other than falling within a range of values. In this case, the TSC will -not be a stable time source, and must be calibrated against a known, stable, -external clock to be a usable source of time. - -Whether the TSC runs at a constant rate or scales with the P-state is model -dependent and must be determined by inspecting CPUID, chipset or vendor -specific MSR fields. - -In addition, some vendors have known bugs where the P-state is actually -compensated for properly during normal operation, but when the processor is -inactive, the P-state may be raised temporarily to service cache misses from -other processors. In such cases, the TSC on halted CPUs could advance faster -than that of non-halted processors. AMD Turion processors are known to have -this problem. - -3.6) TSC and STPCLK / T-states - -External signals given to the processor may also have the effect of stopping -the TSC. This is typically done for thermal emergency power control to prevent -an overheating condition, and typically, there is no way to detect that this -condition has happened. - -3.7) TSC virtualization - VMX - -VMX provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP -instructions, which is enough for full virtualization of TSC in any manner. In -addition, VMX allows passing through the host TSC plus an additional TSC_OFFSET -field specified in the VMCS. Special instructions must be used to read and -write the VMCS field. - -3.8) TSC virtualization - SVM - -SVM provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP -instructions, which is enough for full virtualization of TSC in any manner. In -addition, SVM allows passing through the host TSC plus an additional offset -field specified in the SVM control block. - -3.9) TSC feature bits in Linux - -In summary, there is no way to guarantee the TSC remains in perfect -synchronization unless it is explicitly guaranteed by the architecture. Even -if so, the TSCs in multi-sockets or NUMA systems may still run independently -despite being locally consistent. - -The following feature bits are used by Linux to signal various TSC attributes, -but they can only be taken to be meaningful for UP or single node systems. - -X86_FEATURE_TSC : The TSC is available in hardware -X86_FEATURE_RDTSCP : The RDTSCP instruction is available -X86_FEATURE_CONSTANT_TSC : The TSC rate is unchanged with P-states -X86_FEATURE_NONSTOP_TSC : The TSC does not stop in C-states -X86_FEATURE_TSC_RELIABLE : TSC sync checks are skipped (VMware) - -4) Virtualization Problems - -Timekeeping is especially problematic for virtualization because a number of -challenges arise. The most obvious problem is that time is now shared between -the host and, potentially, a number of virtual machines. Thus the virtual -operating system does not run with 100% usage of the CPU, despite the fact that -it may very well make that assumption. It may expect it to remain true to very -exacting bounds when interrupt sources are disabled, but in reality only its -virtual interrupt sources are disabled, and the machine may still be preempted -at any time. This causes problems as the passage of real time, the injection -of machine interrupts and the associated clock sources are no longer completely -synchronized with real time. - -This same problem can occur on native harware to a degree, as SMM mode may -steal cycles from the naturally on X86 systems when SMM mode is used by the -BIOS, but not in such an extreme fashion. However, the fact that SMM mode may -cause similar problems to virtualization makes it a good justification for -solving many of these problems on bare metal. - -4.1) Interrupt clocking - -One of the most immediate problems that occurs with legacy operating systems -is that the system timekeeping routines are often designed to keep track of -time by counting periodic interrupts. These interrupts may come from the PIT -or the RTC, but the problem is the same: the host virtualization engine may not -be able to deliver the proper number of interrupts per second, and so guest -time may fall behind. This is especially problematic if a high interrupt rate -is selected, such as 1000 HZ, which is unfortunately the default for many Linux -guests. - -There are three approaches to solving this problem; first, it may be possible -to simply ignore it. Guests which have a separate time source for tracking -'wall clock' or 'real time' may not need any adjustment of their interrupts to -maintain proper time. If this is not sufficient, it may be necessary to inject -additional interrupts into the guest in order to increase the effective -interrupt rate. This approach leads to complications in extreme conditions, -where host load or guest lag is too much to compensate for, and thus another -solution to the problem has risen: the guest may need to become aware of lost -ticks and compensate for them internally. Although promising in theory, the -implementation of this policy in Linux has been extremely error prone, and a -number of buggy variants of lost tick compensation are distributed across -commonly used Linux systems. - -Windows uses periodic RTC clocking as a means of keeping time internally, and -thus requires interrupt slewing to keep proper time. It does use a low enough -rate (ed: is it 18.2 Hz?) however that it has not yet been a problem in -practice. - -4.2) TSC sampling and serialization - -As the highest precision time source available, the cycle counter of the CPU -has aroused much interest from developers. As explained above, this timer has -many problems unique to its nature as a local, potentially unstable and -potentially unsynchronized source. One issue which is not unique to the TSC, -but is highlighted because of its very precise nature is sampling delay. By -definition, the counter, once read is already old. However, it is also -possible for the counter to be read ahead of the actual use of the result. -This is a consequence of the superscalar execution of the instruction stream, -which may execute instructions out of order. Such execution is called -non-serialized. Forcing serialized execution is necessary for precise -measurement with the TSC, and requires a serializing instruction, such as CPUID -or an MSR read. - -Since CPUID may actually be virtualized by a trap and emulate mechanism, this -serialization can pose a performance issue for hardware virtualization. An -accurate time stamp counter reading may therefore not always be available, and -it may be necessary for an implementation to guard against "backwards" reads of -the TSC as seen from other CPUs, even in an otherwise perfectly synchronized -system. - -4.3) Timespec aliasing - -Additionally, this lack of serialization from the TSC poses another challenge -when using results of the TSC when measured against another time source. As -the TSC is much higher precision, many possible values of the TSC may be read -while another clock is still expressing the same value. - -That is, you may read (T,T+10) while external clock C maintains the same value. -Due to non-serialized reads, you may actually end up with a range which -fluctuates - from (T-1.. T+10). Thus, any time calculated from a TSC, but -calibrated against an external value may have a range of valid values. -Re-calibrating this computation may actually cause time, as computed after the -calibration, to go backwards, compared with time computed before the -calibration. - -This problem is particularly pronounced with an internal time source in Linux, -the kernel time, which is expressed in the theoretically high resolution -timespec - but which advances in much larger granularity intervals, sometimes -at the rate of jiffies, and possibly in catchup modes, at a much larger step. - -This aliasing requires care in the computation and recalibration of kvmclock -and any other values derived from TSC computation (such as TSC virtualization -itself). - -4.4) Migration - -Migration of a virtual machine raises problems for timekeeping in two ways. -First, the migration itself may take time, during which interrupts cannot be -delivered, and after which, the guest time may need to be caught up. NTP may -be able to help to some degree here, as the clock correction required is -typically small enough to fall in the NTP-correctable window. - -An additional concern is that timers based off the TSC (or HPET, if the raw bus -clock is exposed) may now be running at different rates, requiring compensation -in some way in the hypervisor by virtualizing these timers. In addition, -migrating to a faster machine may preclude the use of a passthrough TSC, as a -faster clock cannot be made visible to a guest without the potential of time -advancing faster than usual. A slower clock is less of a problem, as it can -always be caught up to the original rate. KVM clock avoids these problems by -simply storing multipliers and offsets against the TSC for the guest to convert -back into nanosecond resolution values. - -4.5) Scheduling - -Since scheduling may be based on precise timing and firing of interrupts, the -scheduling algorithms of an operating system may be adversely affected by -virtualization. In theory, the effect is random and should be universally -distributed, but in contrived as well as real scenarios (guest device access, -causes of virtualization exits, possible context switch), this may not always -be the case. The effect of this has not been well studied. - -In an attempt to work around this, several implementations have provided a -paravirtualized scheduler clock, which reveals the true amount of CPU time for -which a virtual machine has been running. - -4.6) Watchdogs - -Watchdog timers, such as the lock detector in Linux may fire accidentally when -running under hardware virtualization due to timer interrupts being delayed or -misinterpretation of the passage of real time. Usually, these warnings are -spurious and can be ignored, but in some circumstances it may be necessary to -disable such detection. - -4.7) Delays and precision timing - -Precise timing and delays may not be possible in a virtualized system. This -can happen if the system is controlling physical hardware, or issues delays to -compensate for slower I/O to and from devices. The first issue is not solvable -in general for a virtualized system; hardware control software can't be -adequately virtualized without a full real-time operating system, which would -require an RT aware virtualization platform. - -The second issue may cause performance problems, but this is unlikely to be a -significant issue. In many cases these delays may be eliminated through -configuration or paravirtualization. - -4.8) Covert channels and leaks - -In addition to the above problems, time information will inevitably leak to the -guest about the host in anything but a perfect implementation of virtualized -time. This may allow the guest to infer the presence of a hypervisor (as in a -red-pill type detection), and it may allow information to leak between guests -by using CPU utilization itself as a signalling channel. Preventing such -problems would require completely isolated virtual time which may not track -real time any longer. This may be useful in certain security or QA contexts, -but in general isn't recommended for real-world deployment scenarios. diff --git a/trunk/Documentation/vm/numa_memory_policy.txt b/trunk/Documentation/vm/numa_memory_policy.txt index 4e7da6543424..6690fc34ef6d 100644 --- a/trunk/Documentation/vm/numa_memory_policy.txt +++ b/trunk/Documentation/vm/numa_memory_policy.txt @@ -424,7 +424,7 @@ a command line tool, numactl(8), exists that allows one to: + set the shared policy for a shared memory segment via mbind(2) -The numactl(8) tool is packaged with the run-time version of the library +The numactl(8) tool is packages with the run-time version of the library containing the memory policy system call wrappers. Some distributions package the headers and compile-time libraries in a separate development package. diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 69aa8fe060b3..494e1a07366a 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2212,13 +2212,6 @@ W: bluesmoke.sourceforge.net S: Maintained F: drivers/edac/i5400_edac.c -EDAC-I7300 -M: Mauro Carvalho Chehab -L: linux-edac@vger.kernel.org -W: bluesmoke.sourceforge.net -S: Maintained -F: drivers/edac/i7300_edac.c - EDAC-I7CORE M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org @@ -3441,7 +3434,7 @@ F: scripts/package/ KERNEL JANITORS L: kernel-janitors@vger.kernel.org -W: http://kernelnewbies.org/KernelJanitors +W: http://janitor.kernelnewbies.org/ S: Odd Fixes KERNEL NFSD, SUNRPC, AND LOCKD SERVERS @@ -4460,15 +4453,6 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-pasemi.c -PADATA PARALLEL EXECUTION MECHANISM -M: Steffen Klassert -L: linux-kernel@vger.kernel.org -L: linux-crypto@vger.kernel.org -S: Maintained -F: kernel/padata.c -F: include/linux/padata.h -F: Documentation/padata.txt - PANASONIC LAPTOP ACPI EXTRAS DRIVER M: Harald Welte L: platform-driver-x86@vger.kernel.org @@ -4548,12 +4532,6 @@ S: Maintained F: drivers/leds/leds-pca9532.c F: include/linux/leds-pca9532.h -PCA9541 I2C BUS MASTER SELECTOR DRIVER -M: Guenter Roeck -L: linux-i2c@vger.kernel.org -S: Maintained -F: drivers/i2c/muxes/pca9541.c - PCA9564/PCA9665 I2C BUS DRIVER M: Wolfram Sang L: linux-i2c@vger.kernel.org @@ -4602,13 +4580,6 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/pcnet32.c -PCRYPT PARALLEL CRYPTO ENGINE -M: Steffen Klassert -L: linux-crypto@vger.kernel.org -S: Maintained -F: crypto/pcrypt.c -F: include/crypto/pcrypt.h - PER-TASK DELAY ACCOUNTING M: Balbir Singh S: Maintained diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index b64e465ac49c..3849887157e7 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -1222,7 +1222,7 @@ config SMP See also , and the SMP-HOWTO available at - . + . If you don't know what to do here, say N. diff --git a/trunk/arch/arm/common/icst.c b/trunk/arch/arm/common/icst.c index 2dc6da70ae59..9a7f09cff300 100644 --- a/trunk/arch/arm/common/icst.c +++ b/trunk/arch/arm/common/icst.c @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * Support functions for calculating clocks/divisors for the ICST307 - * clock generators. See http://www.idt.com/ for more information + * clock generators. See http://www.icst.com/ for more information * on these devices. * * This is an almost identical implementation to the ICST525 clock generator. diff --git a/trunk/arch/arm/common/scoop.c b/trunk/arch/arm/common/scoop.c index c11af1e4bad3..9012004321dd 100644 --- a/trunk/arch/arm/common/scoop.c +++ b/trunk/arch/arm/common/scoop.c @@ -44,12 +44,12 @@ void reset_scoop(struct device *dev) { struct scoop_dev *sdev = dev_get_drvdata(dev); - iowrite16(0x0100, sdev->base + SCOOP_MCR); /* 00 */ - iowrite16(0x0000, sdev->base + SCOOP_CDR); /* 04 */ - iowrite16(0x0000, sdev->base + SCOOP_CCR); /* 10 */ - iowrite16(0x0000, sdev->base + SCOOP_IMR); /* 18 */ - iowrite16(0x00FF, sdev->base + SCOOP_IRM); /* 14 */ - iowrite16(0x0000, sdev->base + SCOOP_ISR); /* 1C */ + iowrite16(0x0100, sdev->base + SCOOP_MCR); // 00 + iowrite16(0x0000, sdev->base + SCOOP_CDR); // 04 + iowrite16(0x0000, sdev->base + SCOOP_CCR); // 10 + iowrite16(0x0000, sdev->base + SCOOP_IMR); // 18 + iowrite16(0x00FF, sdev->base + SCOOP_IRM); // 14 + iowrite16(0x0000, sdev->base + SCOOP_ISR); // 1C iowrite16(0x0000, sdev->base + SCOOP_IRM); } diff --git a/trunk/arch/arm/common/uengine.c b/trunk/arch/arm/common/uengine.c index bef408f3d76c..b520e56216a9 100644 --- a/trunk/arch/arm/common/uengine.c +++ b/trunk/arch/arm/common/uengine.c @@ -312,16 +312,16 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) b1 = (gpr_a[i] >> 8) & 0xff; b0 = gpr_a[i] & 0xff; - /* immed[@ai, (b1 << 8) | b0] */ - /* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */ + // immed[@ai, (b1 << 8) | b0] + // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII ucode[offset++] = 0xf0; ucode[offset++] = (b1 >> 4); ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6); ucode[offset++] = (b0 << 2); ucode[offset++] = 0x80 | i; - /* immed_w1[@ai, (b3 << 8) | b2] */ - /* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */ + // immed_w1[@ai, (b3 << 8) | b2] + // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII ucode[offset++] = 0xf4; ucode[offset++] = 0x40 | (b3 >> 4); ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6); @@ -340,16 +340,16 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) b1 = (gpr_b[i] >> 8) & 0xff; b0 = gpr_b[i] & 0xff; - /* immed[@bi, (b1 << 8) | b0] */ - /* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */ + // immed[@bi, (b1 << 8) | b0] + // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV ucode[offset++] = 0xf0; ucode[offset++] = (b1 >> 4); ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6); ucode[offset++] = (i << 2) | 0x03; ucode[offset++] = b0; - /* immed_w1[@bi, (b3 << 8) | b2] */ - /* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */ + // immed_w1[@bi, (b3 << 8) | b2] + // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV ucode[offset++] = 0xf4; ucode[offset++] = 0x40 | (b3 >> 4); ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6); @@ -357,7 +357,7 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) ucode[offset++] = b2; } - /* ctx_arb[kill] */ + // ctx_arb[kill] ucode[offset++] = 0xe0; ucode[offset++] = 0x00; ucode[offset++] = 0x01; diff --git a/trunk/arch/arm/include/asm/hardware/icst.h b/trunk/arch/arm/include/asm/hardware/icst.h index 794220b087d2..10382a3dcec9 100644 --- a/trunk/arch/arm/include/asm/hardware/icst.h +++ b/trunk/arch/arm/include/asm/hardware/icst.h @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * Support functions for calculating clocks/divisors for the ICST - * clock generators. See http://www.idt.com/ for more information + * clock generators. See http://www.icst.com/ for more information * on these devices. */ #ifndef ASMARM_HARDWARE_ICST_H diff --git a/trunk/arch/arm/mach-at91/Kconfig b/trunk/arch/arm/mach-at91/Kconfig index abed4d15a7fd..851e8139ef9d 100644 --- a/trunk/arch/arm/mach-at91/Kconfig +++ b/trunk/arch/arm/mach-at91/Kconfig @@ -109,7 +109,7 @@ config MACH_ONEARM bool "Ajeco 1ARM Single Board Computer" help Select this if you are using Ajeco's 1ARM Single Board Computer. - + config ARCH_AT91RM9200DK bool "Atmel AT91RM9200-DK Development board" @@ -141,7 +141,7 @@ config MACH_CARMEVA bool "Conitec ARM&EVA" help Select this if you are using Conitec's AT91RM9200-MCU-Module. - + config MACH_ATEB9200 bool "Embest ATEB9200" @@ -153,7 +153,7 @@ config MACH_KB9200 bool "KwikByte KB920x" help Select this if you are using KwikByte's KB920x board. - + config MACH_PICOTUX2XX bool "picotux 200" diff --git a/trunk/arch/arm/mach-omap1/Kconfig b/trunk/arch/arm/mach-omap1/Kconfig index 5f6496375404..3b02d3b944af 100644 --- a/trunk/arch/arm/mach-omap1/Kconfig +++ b/trunk/arch/arm/mach-omap1/Kconfig @@ -128,7 +128,7 @@ config MACH_OMAP_PALMTT help Support for the Palm Tungsten|T PDA. To boot the kernel, you'll need a PalmOS compatible bootloader (Garux); check out - http://garux.sourceforge.net/ for more information. + http://www.hackndev.com/palm/tt/ for more information. Say Y here if you have this PDA model, say N otherwise. config MACH_SX1 diff --git a/trunk/arch/arm/mach-omap2/clock2420_data.c b/trunk/arch/arm/mach-omap2/clock2420_data.c index 5f2066a6ba74..37d65d62ed8f 100644 --- a/trunk/arch/arm/mach-omap2/clock2420_data.c +++ b/trunk/arch/arm/mach-omap2/clock2420_data.c @@ -1838,7 +1838,7 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "des_ick", &des_ick, CK_242X), CLK("omap-sham", "ick", &sha_ick, CK_242X), CLK("omap_rng", "ick", &rng_ick, CK_242X), - CLK("omap-aes", "ick", &aes_ick, CK_242X), + CLK(NULL, "aes_ick", &aes_ick, CK_242X), CLK(NULL, "pka_ick", &pka_ick, CK_242X), CLK(NULL, "usb_fck", &usb_fck, CK_242X), CLK("musb_hdrc", "fck", &osc_ck, CK_242X), diff --git a/trunk/arch/arm/mach-omap2/clock2430_data.c b/trunk/arch/arm/mach-omap2/clock2430_data.c index 701a1716019e..b33118fb6a87 100644 --- a/trunk/arch/arm/mach-omap2/clock2430_data.c +++ b/trunk/arch/arm/mach-omap2/clock2430_data.c @@ -1926,7 +1926,7 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "des_ick", &des_ick, CK_243X), CLK("omap-sham", "ick", &sha_ick, CK_243X), CLK("omap_rng", "ick", &rng_ick, CK_243X), - CLK("omap-aes", "ick", &aes_ick, CK_243X), + CLK(NULL, "aes_ick", &aes_ick, CK_243X), CLK(NULL, "pka_ick", &pka_ick, CK_243X), CLK(NULL, "usb_fck", &usb_fck, CK_243X), CLK("musb_hdrc", "ick", &usbhs_ick, CK_243X), diff --git a/trunk/arch/arm/mach-omap2/clock3xxx_data.c b/trunk/arch/arm/mach-omap2/clock3xxx_data.c index c73906d17458..dfdce2d82779 100644 --- a/trunk/arch/arm/mach-omap2/clock3xxx_data.c +++ b/trunk/arch/arm/mach-omap2/clock3xxx_data.c @@ -3288,7 +3288,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2 | CK_AM35XX), CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2 | CK_AM35XX), CLK(NULL, "icr_ick", &icr_ick, CK_343X), - CLK("omap-aes", "ick", &aes2_ick, CK_343X), + CLK(NULL, "aes2_ick", &aes2_ick, CK_343X), CLK("omap-sham", "ick", &sha12_ick, CK_343X), CLK(NULL, "des2_ick", &des2_ick, CK_343X), CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_3XXX), diff --git a/trunk/arch/arm/mach-omap2/devices.c b/trunk/arch/arm/mach-omap2/devices.c index b27e7cbb3f29..2dbb265bedd4 100644 --- a/trunk/arch/arm/mach-omap2/devices.c +++ b/trunk/arch/arm/mach-omap2/devices.c @@ -498,76 +498,6 @@ static void omap_init_sham(void) static inline void omap_init_sham(void) { } #endif -#if defined(CONFIG_CRYPTO_DEV_OMAP_AES) || defined(CONFIG_CRYPTO_DEV_OMAP_AES_MODULE) - -#ifdef CONFIG_ARCH_OMAP24XX -static struct resource omap2_aes_resources[] = { - { - .start = OMAP24XX_SEC_AES_BASE, - .end = OMAP24XX_SEC_AES_BASE + 0x4C, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP24XX_DMA_AES_TX, - .flags = IORESOURCE_DMA, - }, - { - .start = OMAP24XX_DMA_AES_RX, - .flags = IORESOURCE_DMA, - } -}; -static int omap2_aes_resources_sz = ARRAY_SIZE(omap2_aes_resources); -#else -#define omap2_aes_resources NULL -#define omap2_aes_resources_sz 0 -#endif - -#ifdef CONFIG_ARCH_OMAP34XX -static struct resource omap3_aes_resources[] = { - { - .start = OMAP34XX_SEC_AES_BASE, - .end = OMAP34XX_SEC_AES_BASE + 0x4C, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP34XX_DMA_AES2_TX, - .flags = IORESOURCE_DMA, - }, - { - .start = OMAP34XX_DMA_AES2_RX, - .flags = IORESOURCE_DMA, - } -}; -static int omap3_aes_resources_sz = ARRAY_SIZE(omap3_aes_resources); -#else -#define omap3_aes_resources NULL -#define omap3_aes_resources_sz 0 -#endif - -static struct platform_device aes_device = { - .name = "omap-aes", - .id = -1, -}; - -static void omap_init_aes(void) -{ - if (cpu_is_omap24xx()) { - aes_device.resource = omap2_aes_resources; - aes_device.num_resources = omap2_aes_resources_sz; - } else if (cpu_is_omap34xx()) { - aes_device.resource = omap3_aes_resources; - aes_device.num_resources = omap3_aes_resources_sz; - } else { - pr_err("%s: platform not supported\n", __func__); - return; - } - platform_device_register(&aes_device); -} - -#else -static inline void omap_init_aes(void) { } -#endif - /*-------------------------------------------------------------------------*/ #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) @@ -924,7 +854,6 @@ static int __init omap2_init_devices(void) omap_hdq_init(); omap_init_sti(); omap_init_sham(); - omap_init_aes(); omap_init_vout(); return 0; diff --git a/trunk/arch/arm/mach-omap2/hsmmc.h b/trunk/arch/arm/mach-omap2/hsmmc.h index 0f8a2e6ee284..1fe6f0187177 100644 --- a/trunk/arch/arm/mach-omap2/hsmmc.h +++ b/trunk/arch/arm/mach-omap2/hsmmc.h @@ -23,7 +23,7 @@ struct omap2_hsmmc_info { char *name; /* or NULL for default */ struct device *dev; /* returned: pointer to mmc adapter */ int ocr_mask; /* temporary HACK */ - /* Remux (pad configuration) when powering on/off */ + /* Remux (pad configuation) when powering on/off */ void (*remux)(struct device *dev, int slot, int power_on); /* init some special card */ void (*init_card)(struct mmc_card *card); diff --git a/trunk/arch/arm/mach-s3c2440/mach-at2440evb.c b/trunk/arch/arm/mach-s3c2440/mach-at2440evb.c index 6c98b789b8c6..e3810c86a5e6 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-at2440evb.c +++ b/trunk/arch/arm/mach-s3c2440/mach-at2440evb.c @@ -5,7 +5,7 @@ * and modifications by SBZ and * Weibing * - * For product information, visit http://www.arm.com/ + * For product information, visit http://www.arm9e.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/trunk/arch/arm/mach-sa1100/Kconfig b/trunk/arch/arm/mach-sa1100/Kconfig index 5da8c35aa0de..fd4c52b7ccb6 100644 --- a/trunk/arch/arm/mach-sa1100/Kconfig +++ b/trunk/arch/arm/mach-sa1100/Kconfig @@ -90,8 +90,8 @@ config SA1100_JORNADA720 # FIXME: select CPU_FREQ_SA11x0 help Say Y here if you want to build a kernel for the HP Jornada 720 - handheld computer. See - + handheld computer. See + for details. config SA1100_JORNADA720_SSP bool "HP Jornada 720 Extended SSP driver" @@ -145,7 +145,7 @@ config SA1100_SIMPAD FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same like CL4 in additional it has a PCMCIA-Slot. For more information - visit or . + visit or . config SA1100_SSP tristate "Generic PIO SSP" diff --git a/trunk/arch/arm/mach-sa1100/cpu-sa1100.c b/trunk/arch/arm/mach-sa1100/cpu-sa1100.c index c0a13ef5436f..ef817876a5d6 100644 --- a/trunk/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/trunk/arch/arm/mach-sa1100/cpu-sa1100.c @@ -13,7 +13,7 @@ * This software has been developed while working on the LART * computing board (http://www.lartmaker.nl/), which is * sponsored by the Mobile Multi-media Communications - * (http://www.mobimedia.org/) and Ubiquitous Communications + * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications * (http://www.ubicom.tudelft.nl/) projects. * * The authors can be reached at: diff --git a/trunk/arch/arm/nwfpe/milieu.h b/trunk/arch/arm/nwfpe/milieu.h index 09a4f2ddeb77..a3892ab2dca4 100644 --- a/trunk/arch/arm/nwfpe/milieu.h +++ b/trunk/arch/arm/nwfpe/milieu.h @@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page -http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT diff --git a/trunk/arch/arm/nwfpe/softfloat-macros b/trunk/arch/arm/nwfpe/softfloat-macros index cf2a6173149e..5a060f95a58f 100644 --- a/trunk/arch/arm/nwfpe/softfloat-macros +++ b/trunk/arch/arm/nwfpe/softfloat-macros @@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the web page -http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT diff --git a/trunk/arch/arm/nwfpe/softfloat-specialize b/trunk/arch/arm/nwfpe/softfloat-specialize index 679a0269dd25..d4a4c8e06635 100644 --- a/trunk/arch/arm/nwfpe/softfloat-specialize +++ b/trunk/arch/arm/nwfpe/softfloat-specialize @@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page -http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT diff --git a/trunk/arch/arm/nwfpe/softfloat.c b/trunk/arch/arm/nwfpe/softfloat.c index ffa6b438786b..0f9656e482ba 100644 --- a/trunk/arch/arm/nwfpe/softfloat.c +++ b/trunk/arch/arm/nwfpe/softfloat.c @@ -11,8 +11,8 @@ National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the web page -http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT diff --git a/trunk/arch/arm/nwfpe/softfloat.h b/trunk/arch/arm/nwfpe/softfloat.h index df4d243a2b7c..13e479c5da57 100644 --- a/trunk/arch/arm/nwfpe/softfloat.h +++ b/trunk/arch/arm/nwfpe/softfloat.h @@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page -http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT diff --git a/trunk/arch/arm/plat-samsung/include/plat/adc.h b/trunk/arch/arm/plat-samsung/include/plat/adc.h index b258a08de591..e8382c7be10b 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/adc.h +++ b/trunk/arch/arm/plat-samsung/include/plat/adc.h @@ -1,7 +1,7 @@ /* arch/arm/plat-samsung/include/plat/adc.h * * Copyright (c) 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ + * http://armlinux.simnte.co.uk/ * Ben Dooks * * S3C ADC driver information diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index f0dc5b8075a7..9ac87255a03a 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -146,7 +146,7 @@ config BOARD_HAMMERHEAD will cover even the most exceptional need of memory bandwidth. Together with the onboard video decoder the board is ready for video processing. - For more information see: http://www.miromico.ch/index.php/hammerhead.html + For more information see: http://www.miromico.com/hammerhead config BOARD_FAVR_32 bool "Favr-32 LCD-board" diff --git a/trunk/arch/blackfin/mach-bf527/boards/ezkit.c b/trunk/arch/blackfin/mach-bf527/boards/ezkit.c index df82723fb504..07c132dc4125 100644 --- a/trunk/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/trunk/arch/blackfin/mach-bf527/boards/ezkit.c @@ -887,7 +887,7 @@ static struct adp5520_keys_platform_data adp5520_keys_data = { }; /* - * ADP5520/5501 Multifunction Device Init Data + * ADP5520/5501 Multifuction Device Init Data */ static struct adp5520_platform_data adp5520_pdev_data = { diff --git a/trunk/arch/blackfin/mach-bf537/boards/stamp.c b/trunk/arch/blackfin/mach-bf537/boards/stamp.c index cd2c797c8c9f..c9e0e85629bf 100644 --- a/trunk/arch/blackfin/mach-bf537/boards/stamp.c +++ b/trunk/arch/blackfin/mach-bf537/boards/stamp.c @@ -2015,7 +2015,7 @@ static struct adp5520_keys_platform_data adp5520_keys_data = { }; /* - * ADP5520/5501 Multifunction Device Init Data + * ADP5520/5501 Multifuction Device Init Data */ static struct adp5520_platform_data adp5520_pdev_data = { diff --git a/trunk/arch/h8300/Kconfig.cpu b/trunk/arch/h8300/Kconfig.cpu index d236ab4232ca..6e2ecff199c5 100644 --- a/trunk/arch/h8300/Kconfig.cpu +++ b/trunk/arch/h8300/Kconfig.cpu @@ -17,7 +17,7 @@ config H8300H_AKI3068NET help AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support More Information. (Japanese Only) - + AE-3068/69 Evaluation Board Support More Information. @@ -36,7 +36,7 @@ config H8300H_SIM help GDB Simulator Support More Information. - + arch/h8300/Doc/simulator.txt config H8S_GENERIC bool "H8S Generic" @@ -50,14 +50,14 @@ config H8S_EDOSK2674 Renesas EDOSK-2674 Evaluation Board Support More Information. - + config H8S_SIM bool "H8S Simulator" help GDB Simulator Support More Information. - + arch/h8300/Doc/simulator.txt endchoice diff --git a/trunk/arch/h8300/README b/trunk/arch/h8300/README index 637f5a02f311..2fd6f6d7a019 100644 --- a/trunk/arch/h8300/README +++ b/trunk/arch/h8300/README @@ -18,7 +18,6 @@ H8/300H and H8S 4.EDOSK2674 see http://www.eu.renesas.com/products/mpumcu/tool/edk/support/edosk2674.html - http://www.uclinux.org/pub/uClinux/ports/h8/HITACHI-EDOSK2674-HOWTO http://www.azpower.com/H8-uClinux/ * Toolchain Version diff --git a/trunk/arch/ia64/kvm/lapic.h b/trunk/arch/ia64/kvm/lapic.h index c5f92a926a9a..ee541cebcd78 100644 --- a/trunk/arch/ia64/kvm/lapic.h +++ b/trunk/arch/ia64/kvm/lapic.h @@ -25,6 +25,5 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); #define kvm_apic_present(x) (true) -#define kvm_lapic_enabled(x) (true) #endif diff --git a/trunk/arch/m32r/Kconfig b/trunk/arch/m32r/Kconfig index 3867fd21f333..836abbbc9c04 100644 --- a/trunk/arch/m32r/Kconfig +++ b/trunk/arch/m32r/Kconfig @@ -315,7 +315,7 @@ config SMP Management" code will be disabled if you say Y here. See also the SMP-HOWTO available at - . + . If you don't know what to do here, say N. diff --git a/trunk/arch/m68k/include/asm/cacheflush_no.h b/trunk/arch/m68k/include/asm/cacheflush_no.h index 7085bd51668b..89f195656be7 100644 --- a/trunk/arch/m68k/include/asm/cacheflush_no.h +++ b/trunk/arch/m68k/include/asm/cacheflush_no.h @@ -29,7 +29,7 @@ static inline void __flush_cache_all(void) { -#if defined(CONFIG_M5407) || defined(CONFIG_M548x) +#ifdef CONFIG_M5407 /* * Use cpushl to push and invalidate all cache lines. * Gas doesn't seem to know how to generate the ColdFire diff --git a/trunk/arch/m68k/include/asm/coldfire.h b/trunk/arch/m68k/include/asm/coldfire.h index 3b0a34d0fe33..83a9fa4e618a 100644 --- a/trunk/arch/m68k/include/asm/coldfire.h +++ b/trunk/arch/m68k/include/asm/coldfire.h @@ -32,9 +32,7 @@ */ #define MCF_MBAR 0x10000000 #define MCF_MBAR2 0x80000000 -#if defined(CONFIG_M548x) -#define MCF_IPSBAR MCF_MBAR -#elif defined(CONFIG_M520x) +#if defined(CONFIG_M520x) #define MCF_IPSBAR 0xFC000000 #else #define MCF_IPSBAR 0x40000000 diff --git a/trunk/arch/m68k/include/asm/gpio.h b/trunk/arch/m68k/include/asm/gpio.h index 1b57adbafad5..283214dc65a7 100644 --- a/trunk/arch/m68k/include/asm/gpio.h +++ b/trunk/arch/m68k/include/asm/gpio.h @@ -36,8 +36,7 @@ */ #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ defined(CONFIG_M520x) || defined(CONFIG_M523x) || \ - defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M532x) || defined(CONFIG_M548x) + defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x) /* These parts have GPIO organized by 8 bit ports */ @@ -137,8 +136,6 @@ static inline u32 __mcf_gpio_ppdr(unsigned gpio) #endif else return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START); -#else - return 0; #endif } @@ -176,8 +173,6 @@ static inline u32 __mcf_gpio_podr(unsigned gpio) #endif else return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START); -#else - return 0; #endif } diff --git a/trunk/arch/m68k/include/asm/m548xgpt.h b/trunk/arch/m68k/include/asm/m548xgpt.h deleted file mode 100644 index c8ef158a1c4e..000000000000 --- a/trunk/arch/m68k/include/asm/m548xgpt.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * File: m548xgpt.h - * Purpose: Register and bit definitions for the MCF548X - * - * Notes: - * - */ - -#ifndef m548xgpt_h -#define m548xgpt_h - -/********************************************************************* -* -* General Purpose Timers (GPT) -* -*********************************************************************/ - -/* Register read/write macros */ -#define MCF_GPT_GMS0 0x000800 -#define MCF_GPT_GCIR0 0x000804 -#define MCF_GPT_GPWM0 0x000808 -#define MCF_GPT_GSR0 0x00080C -#define MCF_GPT_GMS1 0x000810 -#define MCF_GPT_GCIR1 0x000814 -#define MCF_GPT_GPWM1 0x000818 -#define MCF_GPT_GSR1 0x00081C -#define MCF_GPT_GMS2 0x000820 -#define MCF_GPT_GCIR2 0x000824 -#define MCF_GPT_GPWM2 0x000828 -#define MCF_GPT_GSR2 0x00082C -#define MCF_GPT_GMS3 0x000830 -#define MCF_GPT_GCIR3 0x000834 -#define MCF_GPT_GPWM3 0x000838 -#define MCF_GPT_GSR3 0x00083C -#define MCF_GPT_GMS(x) (0x000800+((x)*0x010)) -#define MCF_GPT_GCIR(x) (0x000804+((x)*0x010)) -#define MCF_GPT_GPWM(x) (0x000808+((x)*0x010)) -#define MCF_GPT_GSR(x) (0x00080C+((x)*0x010)) - -/* Bit definitions and macros for MCF_GPT_GMS */ -#define MCF_GPT_GMS_TMS(x) (((x)&0x00000007)<<0) -#define MCF_GPT_GMS_GPIO(x) (((x)&0x00000003)<<4) -#define MCF_GPT_GMS_IEN (0x00000100) -#define MCF_GPT_GMS_OD (0x00000200) -#define MCF_GPT_GMS_SC (0x00000400) -#define MCF_GPT_GMS_CE (0x00001000) -#define MCF_GPT_GMS_WDEN (0x00008000) -#define MCF_GPT_GMS_ICT(x) (((x)&0x00000003)<<16) -#define MCF_GPT_GMS_OCT(x) (((x)&0x00000003)<<20) -#define MCF_GPT_GMS_OCPW(x) (((x)&0x000000FF)<<24) -#define MCF_GPT_GMS_OCT_FRCLOW (0x00000000) -#define MCF_GPT_GMS_OCT_PULSEHI (0x00100000) -#define MCF_GPT_GMS_OCT_PULSELO (0x00200000) -#define MCF_GPT_GMS_OCT_TOGGLE (0x00300000) -#define MCF_GPT_GMS_ICT_ANY (0x00000000) -#define MCF_GPT_GMS_ICT_RISE (0x00010000) -#define MCF_GPT_GMS_ICT_FALL (0x00020000) -#define MCF_GPT_GMS_ICT_PULSE (0x00030000) -#define MCF_GPT_GMS_GPIO_INPUT (0x00000000) -#define MCF_GPT_GMS_GPIO_OUTLO (0x00000020) -#define MCF_GPT_GMS_GPIO_OUTHI (0x00000030) -#define MCF_GPT_GMS_TMS_DISABLE (0x00000000) -#define MCF_GPT_GMS_TMS_INCAPT (0x00000001) -#define MCF_GPT_GMS_TMS_OUTCAPT (0x00000002) -#define MCF_GPT_GMS_TMS_PWM (0x00000003) -#define MCF_GPT_GMS_TMS_GPIO (0x00000004) - -/* Bit definitions and macros for MCF_GPT_GCIR */ -#define MCF_GPT_GCIR_CNT(x) (((x)&0x0000FFFF)<<0) -#define MCF_GPT_GCIR_PRE(x) (((x)&0x0000FFFF)<<16) - -/* Bit definitions and macros for MCF_GPT_GPWM */ -#define MCF_GPT_GPWM_LOAD (0x00000001) -#define MCF_GPT_GPWM_PWMOP (0x00000100) -#define MCF_GPT_GPWM_WIDTH(x) (((x)&0x0000FFFF)<<16) - -/* Bit definitions and macros for MCF_GPT_GSR */ -#define MCF_GPT_GSR_CAPT (0x00000001) -#define MCF_GPT_GSR_COMP (0x00000002) -#define MCF_GPT_GSR_PWMP (0x00000004) -#define MCF_GPT_GSR_TEXP (0x00000008) -#define MCF_GPT_GSR_PIN (0x00000100) -#define MCF_GPT_GSR_OVF(x) (((x)&0x00000007)<<12) -#define MCF_GPT_GSR_CAPTURE(x) (((x)&0x0000FFFF)<<16) - -/********************************************************************/ - -#endif /* m548xgpt_h */ diff --git a/trunk/arch/m68k/include/asm/m548xsim.h b/trunk/arch/m68k/include/asm/m548xsim.h deleted file mode 100644 index 149135ef30d2..000000000000 --- a/trunk/arch/m68k/include/asm/m548xsim.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * m548xsim.h -- ColdFire 547x/548x System Integration Unit support. - */ - -#ifndef m548xsim_h -#define m548xsim_h - -#define MCFINT_VECBASE 64 - -/* - * Interrupt Controller Registers - */ -#define MCFICM_INTC0 0x0700 /* Base for Interrupt Ctrl 0 */ -#define MCFINTC_IPRH 0x00 /* Interrupt pending 32-63 */ -#define MCFINTC_IPRL 0x04 /* Interrupt pending 1-31 */ -#define MCFINTC_IMRH 0x08 /* Interrupt mask 32-63 */ -#define MCFINTC_IMRL 0x0c /* Interrupt mask 1-31 */ -#define MCFINTC_INTFRCH 0x10 /* Interrupt force 32-63 */ -#define MCFINTC_INTFRCL 0x14 /* Interrupt force 1-31 */ -#define MCFINTC_IRLR 0x18 /* */ -#define MCFINTC_IACKL 0x19 /* */ -#define MCFINTC_ICR0 0x40 /* Base ICR register */ - -/* - * Define system peripheral IRQ usage. - */ -#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */ -#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */ - -/* - * Generic GPIO support - */ -#define MCFGPIO_PIN_MAX 0 /* I am too lazy to count */ -#define MCFGPIO_IRQ_MAX -1 -#define MCFGPIO_IRQ_VECBASE -1 - -/* - * Some PSC related definitions - */ -#define MCF_PAR_PSC(x) (0x000A4F-((x)&0x3)) -#define MCF_PAR_SDA (0x0008) -#define MCF_PAR_SCL (0x0004) -#define MCF_PAR_PSC_TXD (0x04) -#define MCF_PAR_PSC_RXD (0x08) -#define MCF_PAR_PSC_RTS(x) (((x)&0x03)<<4) -#define MCF_PAR_PSC_CTS(x) (((x)&0x03)<<6) -#define MCF_PAR_PSC_CTS_GPIO (0x00) -#define MCF_PAR_PSC_CTS_BCLK (0x80) -#define MCF_PAR_PSC_CTS_CTS (0xC0) -#define MCF_PAR_PSC_RTS_GPIO (0x00) -#define MCF_PAR_PSC_RTS_FSYNC (0x20) -#define MCF_PAR_PSC_RTS_RTS (0x30) -#define MCF_PAR_PSC_CANRX (0x40) - -#endif /* m548xsim_h */ diff --git a/trunk/arch/m68k/include/asm/mcfcache.h b/trunk/arch/m68k/include/asm/mcfcache.h index f49dfc09f70a..c042634fadaa 100644 --- a/trunk/arch/m68k/include/asm/mcfcache.h +++ b/trunk/arch/m68k/include/asm/mcfcache.h @@ -107,7 +107,7 @@ .endm #endif /* CONFIG_M532x */ -#if defined(CONFIG_M5407) || defined(CONFIG_M548x) +#if defined(CONFIG_M5407) /* * Version 4 cores have a true harvard style separate instruction * and data cache. Invalidate and enable cache, also enable write diff --git a/trunk/arch/m68k/include/asm/mcfsim.h b/trunk/arch/m68k/include/asm/mcfsim.h index 6901fd68165b..9c70a67bf85f 100644 --- a/trunk/arch/m68k/include/asm/mcfsim.h +++ b/trunk/arch/m68k/include/asm/mcfsim.h @@ -41,8 +41,6 @@ #elif defined(CONFIG_M5407) #include #include -#elif defined(CONFIG_M548x) -#include #endif /****************************************************************************/ diff --git a/trunk/arch/m68k/include/asm/mcfslt.h b/trunk/arch/m68k/include/asm/mcfslt.h deleted file mode 100644 index d0d0ecba5333..000000000000 --- a/trunk/arch/m68k/include/asm/mcfslt.h +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************/ - -/* - * mcfslt.h -- ColdFire internal Slice (SLT) timer support defines. - * - * (C) Copyright 2004, Greg Ungerer (gerg@snapgear.com) - * (C) Copyright 2009, Philippe De Muyter (phdm@macqel.be) - */ - -/****************************************************************************/ -#ifndef mcfslt_h -#define mcfslt_h -/****************************************************************************/ - -/* - * Get address specific defines for the 547x. - */ -#define MCFSLT_TIMER0 0x900 /* Base address of TIMER0 */ -#define MCFSLT_TIMER1 0x910 /* Base address of TIMER1 */ - - -/* - * Define the SLT timer register set addresses. - */ -#define MCFSLT_STCNT 0x00 /* Terminal count */ -#define MCFSLT_SCR 0x04 /* Control */ -#define MCFSLT_SCNT 0x08 /* Current count */ -#define MCFSLT_SSR 0x0C /* Status */ - -/* - * Bit definitions for the SCR control register. - */ -#define MCFSLT_SCR_RUN 0x04000000 /* Run mode (continuous) */ -#define MCFSLT_SCR_IEN 0x02000000 /* Interrupt enable */ -#define MCFSLT_SCR_TEN 0x01000000 /* Timer enable */ - -/* - * Bit definitions for the SSR status register. - */ -#define MCFSLT_SSR_BE 0x02000000 /* Bus error condition */ -#define MCFSLT_SSR_TE 0x01000000 /* Timeout condition */ - -/****************************************************************************/ -#endif /* mcfslt_h */ diff --git a/trunk/arch/m68k/include/asm/mcfuart.h b/trunk/arch/m68k/include/asm/mcfuart.h index db72e2b889ca..01a8716c5fc5 100644 --- a/trunk/arch/m68k/include/asm/mcfuart.h +++ b/trunk/arch/m68k/include/asm/mcfuart.h @@ -47,11 +47,6 @@ #define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */ #define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */ #define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */ -#elif defined(CONFIG_M548x) -#define MCFUART_BASE1 0x8600 /* on M548x */ -#define MCFUART_BASE2 0x8700 /* on M548x */ -#define MCFUART_BASE3 0x8800 /* on M548x */ -#define MCFUART_BASE4 0x8900 /* on M548x */ #endif @@ -217,9 +212,7 @@ struct mcf_platform_uart { #define MCFUART_URF_RXS 0xc0 /* Receiver status */ #endif -#if defined(CONFIG_M548x) -#define MCFUART_TXFIFOSIZE 512 -#elif defined(CONFIG_M5272) +#if defined(CONFIG_M5272) #define MCFUART_TXFIFOSIZE 25 #else #define MCFUART_TXFIFOSIZE 1 diff --git a/trunk/arch/m68k/kernel/asm-offsets.c b/trunk/arch/m68k/kernel/asm-offsets.c index 78e59b82ebc3..73e5e581245b 100644 --- a/trunk/arch/m68k/kernel/asm-offsets.c +++ b/trunk/arch/m68k/kernel/asm-offsets.c @@ -22,9 +22,13 @@ int main(void) { /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); #ifdef CONFIG_MMU DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); #endif @@ -60,6 +64,14 @@ int main(void) /* bitfields are a bit difficult */ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); + /* offsets into the irq_handler struct */ + DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); + DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); + DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); diff --git a/trunk/arch/m68k/mac/macboing.c b/trunk/arch/m68k/mac/macboing.c index ffaa1f6439ae..05285d08e547 100644 --- a/trunk/arch/m68k/mac/macboing.c +++ b/trunk/arch/m68k/mac/macboing.c @@ -114,8 +114,7 @@ static void mac_init_asc( void ) * 16-bit I/O functionality. The PowerBook 500 series computers * support 16-bit stereo output, but only mono input." * - * Technical Information Library (TIL) article number 16405. - * http://support.apple.com/kb/TA32601 + * http://til.info.apple.com/techinfo.nsf/artnum/n16405 * * --David Kilzer */ diff --git a/trunk/arch/m68k/q40/README b/trunk/arch/m68k/q40/README index f877b7249790..6bdbf4879570 100644 --- a/trunk/arch/m68k/q40/README +++ b/trunk/arch/m68k/q40/README @@ -3,7 +3,7 @@ Linux for the Q40 You may try http://www.geocities.com/SiliconValley/Bay/2602/ for some up to date information. Booter and other tools will be also -available from this place or http://ftp.uni-erlangen.de/pub/unix/Linux/680x0/q40/ +available from this place or ftp.uni-erlangen.de/linux/680x0/q40/ and mirrors. Hints to documentation usually refer to the linux source tree in diff --git a/trunk/arch/m68knommu/Kconfig b/trunk/arch/m68knommu/Kconfig index 9287150e5fb0..2609c394e1df 100644 --- a/trunk/arch/m68knommu/Kconfig +++ b/trunk/arch/m68knommu/Kconfig @@ -59,10 +59,6 @@ config GENERIC_HARDIRQS bool default y -config GENERIC_HARDIRQS_NO__DO_IRQ - bool - default y - config GENERIC_CALIBRATE_DELAY bool default y @@ -175,11 +171,6 @@ config M5407 help Motorola ColdFire 5407 processor support. -config M548x - bool "MCF548x" - help - Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support. - endchoice config M527x @@ -190,7 +181,7 @@ config M527x config COLDFIRE bool - depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x) + depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407) select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB default y diff --git a/trunk/arch/m68knommu/Makefile b/trunk/arch/m68knommu/Makefile index 026ef16fa68e..14042574ac21 100644 --- a/trunk/arch/m68knommu/Makefile +++ b/trunk/arch/m68knommu/Makefile @@ -25,7 +25,6 @@ platform-$(CONFIG_M528x) := 528x platform-$(CONFIG_M5307) := 5307 platform-$(CONFIG_M532x) := 532x platform-$(CONFIG_M5407) := 5407 -platform-$(CONFIG_M548x) := 548x PLATFORM := $(platform-y) board-$(CONFIG_PILOT) := pilot @@ -74,7 +73,6 @@ cpuclass-$(CONFIG_M528x) := coldfire cpuclass-$(CONFIG_M5307) := coldfire cpuclass-$(CONFIG_M532x) := coldfire cpuclass-$(CONFIG_M5407) := coldfire -cpuclass-$(CONFIG_M548x) := coldfire cpuclass-$(CONFIG_M68328) := 68328 cpuclass-$(CONFIG_M68EZ328) := 68328 cpuclass-$(CONFIG_M68VZ328) := 68328 @@ -102,7 +100,6 @@ cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307) cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200) cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307) cflags-$(CONFIG_M5407) := $(call cc-option,-m5407,-m5200) -cflags-$(CONFIG_M548x) := $(call cc-option,-m5407,-m5200) cflags-$(CONFIG_M68328) := -m68000 cflags-$(CONFIG_M68EZ328) := -m68000 cflags-$(CONFIG_M68VZ328) := -m68000 diff --git a/trunk/arch/m68knommu/kernel/.gitignore b/trunk/arch/m68knommu/kernel/.gitignore deleted file mode 100644 index c5f676c3c224..000000000000 --- a/trunk/arch/m68knommu/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/trunk/arch/m68knommu/kernel/asm-offsets.c b/trunk/arch/m68knommu/kernel/asm-offsets.c index ffe02f41ad46..24335022fa2c 100644 --- a/trunk/arch/m68knommu/kernel/asm-offsets.c +++ b/trunk/arch/m68knommu/kernel/asm-offsets.c @@ -21,8 +21,14 @@ int main(void) { /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); @@ -57,7 +63,7 @@ int main(void) DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2); #else /* bitfields are a bit difficult */ - DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); + DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4); #endif /* signal defines */ @@ -69,8 +75,11 @@ int main(void) DEFINE(PT_PTRACED, PT_PTRACED); /* Offsets in thread_info structure */ + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); return 0; } diff --git a/trunk/arch/m68knommu/kernel/ptrace.c b/trunk/arch/m68knommu/kernel/ptrace.c index 6fe7c38cd556..f6be1248d216 100644 --- a/trunk/arch/m68knommu/kernel/ptrace.c +++ b/trunk/arch/m68knommu/kernel/ptrace.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -135,6 +134,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp >>= 16; } else if (addr >= 21 && addr < 49) { tmp = child->thread.fp[addr - 21]; +#ifdef CONFIG_M68KFPU_EMU + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#endif } else if (addr == 49) { tmp = child->mm->start_code; } else if (addr == 50) { @@ -168,6 +175,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } if (addr >= 21 && addr < 48) { +#ifdef CONFIG_M68KFPU_EMU + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } +#endif child->thread.fp[addr - 21] = data; ret = 0; } @@ -242,17 +259,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) +asmlinkage void syscall_trace(void) { - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } } diff --git a/trunk/arch/m68knommu/kernel/setup.c b/trunk/arch/m68knommu/kernel/setup.c index c684adf5dc40..ba92b90d5fbc 100644 --- a/trunk/arch/m68knommu/kernel/setup.c +++ b/trunk/arch/m68knommu/kernel/setup.c @@ -54,6 +54,9 @@ void (*mach_reset)(void); void (*mach_halt)(void); void (*mach_power_off)(void); +#ifdef CONFIG_M68000 + #define CPU "MC68000" +#endif #ifdef CONFIG_M68328 #define CPU "MC68328" #endif diff --git a/trunk/arch/m68knommu/kernel/time.c b/trunk/arch/m68knommu/kernel/time.c index d6ac2a43453c..7089dd9d843b 100644 --- a/trunk/arch/m68knommu/kernel/time.c +++ b/trunk/arch/m68knommu/kernel/time.c @@ -60,16 +60,13 @@ static unsigned long read_rtc_mmss(void) { unsigned int year, mon, day, hour, min, sec; - if (mach_gettod) { + if (mach_gettod) mach_gettod(&year, &mon, &day, &hour, &min, &sec); - if ((year += 1900) < 1970) - year += 100; - } else { - year = 1970; - mon = day = 1; - hour = min = sec = 0; - } + else + year = mon = day = hour = min = sec = 0; + if ((year += 1900) < 1970) + year += 100; return mktime(year, mon, day, hour, min, sec); } diff --git a/trunk/arch/m68knommu/kernel/traps.c b/trunk/arch/m68knommu/kernel/traps.c index a768008dfd06..3739c8f657d7 100644 --- a/trunk/arch/m68knommu/kernel/traps.c +++ b/trunk/arch/m68knommu/kernel/traps.c @@ -179,16 +179,14 @@ static void __show_stack(struct task_struct *task, unsigned long *stack) void bad_super_trap(struct frame *fp) { - int vector = (fp->ptregs.vector >> 2) & 0xff; - console_verbose(); - if (vector < ARRAY_SIZE(vec_names)) + if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) printk (KERN_WARNING "*** %s *** FORMAT=%X\n", - vec_names[vector], + vec_names[(fp->ptregs.vector) >> 2], fp->ptregs.format); else printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", - vector, + (fp->ptregs.vector) >> 2, fp->ptregs.format); printk (KERN_WARNING "Current process id is %d\n", current->pid); die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); @@ -197,11 +195,10 @@ void bad_super_trap(struct frame *fp) asmlinkage void trap_c(struct frame *fp) { int sig; - int vector = (fp->ptregs.vector >> 2) & 0xff; siginfo_t info; if (fp->ptregs.sr & PS_S) { - if (vector == VEC_TRACE) { + if ((fp->ptregs.vector >> 2) == VEC_TRACE) { /* traced a trapping instruction */ } else bad_super_trap(fp); @@ -209,7 +206,7 @@ asmlinkage void trap_c(struct frame *fp) } /* send the appropriate signal to the user program */ - switch (vector) { + switch ((fp->ptregs.vector) >> 2) { case VEC_ADDRERR: info.si_code = BUS_ADRALN; sig = SIGBUS; @@ -363,3 +360,16 @@ void show_stack(struct task_struct *task, unsigned long *stack) else __show_stack(task, stack); } + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif diff --git a/trunk/arch/m68knommu/platform/5206/Makefile b/trunk/arch/m68knommu/platform/5206/Makefile index b5db05625cfa..113c33390064 100644 --- a/trunk/arch/m68knommu/platform/5206/Makefile +++ b/trunk/arch/m68knommu/platform/5206/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5206e/Makefile b/trunk/arch/m68knommu/platform/5206e/Makefile index b5db05625cfa..113c33390064 100644 --- a/trunk/arch/m68knommu/platform/5206e/Makefile +++ b/trunk/arch/m68knommu/platform/5206e/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/520x/Makefile b/trunk/arch/m68knommu/platform/520x/Makefile index ad3f4e5a57ce..435ab3483dc1 100644 --- a/trunk/arch/m68knommu/platform/520x/Makefile +++ b/trunk/arch/m68knommu/platform/520x/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/523x/Makefile b/trunk/arch/m68knommu/platform/523x/Makefile index c04b8f71c88c..b8f9b45440c2 100644 --- a/trunk/arch/m68knommu/platform/523x/Makefile +++ b/trunk/arch/m68knommu/platform/523x/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5249/Makefile b/trunk/arch/m68knommu/platform/5249/Makefile index 4bed30fd0073..f56225d1582f 100644 --- a/trunk/arch/m68knommu/platform/5249/Makefile +++ b/trunk/arch/m68knommu/platform/5249/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5272/Makefile b/trunk/arch/m68knommu/platform/5272/Makefile index 34110fc14301..93673ef8e2c1 100644 --- a/trunk/arch/m68knommu/platform/5272/Makefile +++ b/trunk/arch/m68knommu/platform/5272/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5272/config.c b/trunk/arch/m68knommu/platform/5272/config.c index 65bb582734e1..59278c0887d0 100644 --- a/trunk/arch/m68knommu/platform/5272/config.c +++ b/trunk/arch/m68knommu/platform/5272/config.c @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #include @@ -150,23 +148,9 @@ void __init config_BSP(char *commandp, int size) /***************************************************************************/ -/* - * Some 5272 based boards have the FEC ethernet diectly connected to - * an ethernet switch. In this case we need to use the fixed phy type, - * and we need to declare it early in boot. - */ -static struct fixed_phy_status nettel_fixed_phy_status __initdata = { - .link = 1, - .speed = 100, - .duplex = 0, -}; - -/***************************************************************************/ - static int __init init_BSP(void) { m5272_uarts_init(); - fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status); platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices)); return 0; } diff --git a/trunk/arch/m68knommu/platform/5272/intc.c b/trunk/arch/m68knommu/platform/5272/intc.c index 3cf681c177aa..7081e0a9720e 100644 --- a/trunk/arch/m68knommu/platform/5272/intc.c +++ b/trunk/arch/m68knommu/platform/5272/intc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -30,10 +29,6 @@ * via a set of 4 "Interrupt Controller Registers" (ICR). There is a * loose mapping of vector number to register and internal bits, but * a table is the easiest and quickest way to map them. - * - * Note that the external interrupts are edge triggered (unlike the - * internal interrupt sources which are level triggered). Which means - * they also need acknowledgeing via acknowledge bits. */ struct irqmap { unsigned char icr; @@ -73,11 +68,6 @@ static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = { /*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, }, }; -/* - * The act of masking the interrupt also has a side effect of 'ack'ing - * an interrupt on this irq (for the external irqs). So this mask function - * is also an ack_mask function. - */ static void intc_irq_mask(unsigned int irq) { if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { @@ -105,9 +95,7 @@ static void intc_irq_ack(unsigned int irq) irq -= MCFINT_VECBASE; if (intc_irqmap[irq].ack) { u32 v; - v = readl(MCF_MBAR + intc_irqmap[irq].icr); - v &= (0x7 << intc_irqmap[irq].index); - v |= (0x8 << intc_irqmap[irq].index); + v = 0xd << intc_irqmap[irq].index; writel(v, MCF_MBAR + intc_irqmap[irq].icr); } } @@ -115,47 +103,21 @@ static void intc_irq_ack(unsigned int irq) static int intc_irq_set_type(unsigned int irq, unsigned int type) { - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { - irq -= MCFINT_VECBASE; - if (intc_irqmap[irq].ack) { - u32 v; - v = readl(MCF_MBAR + MCFSIM_PITR); - if (type == IRQ_TYPE_EDGE_FALLING) - v &= ~(0x1 << (32 - irq)); - else - v |= (0x1 << (32 - irq)); - writel(v, MCF_MBAR + MCFSIM_PITR); - } - } + /* We can set the edge type here for external interrupts */ return 0; } -/* - * Simple flow handler to deal with the external edge triggered interrupts. - * We need to be careful with the masking/acking due to the side effects - * of masking an interrupt. - */ -static void intc_external_irq(unsigned int irq, struct irq_desc *desc) -{ - kstat_incr_irqs_this_cpu(irq, desc); - desc->status |= IRQ_INPROGRESS; - desc->chip->ack(irq); - handle_IRQ_event(irq, desc->action); - desc->status &= ~IRQ_INPROGRESS; -} - static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, - .mask_ack = intc_irq_mask, .ack = intc_irq_ack, .set_type = intc_irq_set_type, }; void __init init_IRQ(void) { - int irq, edge; + int irq; init_vectors(); @@ -166,17 +128,11 @@ void __init init_IRQ(void) writel(0x88888888, MCF_MBAR + MCFSIM_ICR4); for (irq = 0; (irq < NR_IRQS); irq++) { - set_irq_chip(irq, &intc_irq_chip); - edge = 0; - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) - edge = intc_irqmap[irq - MCFINT_VECBASE].ack; - if (edge) { - set_irq_type(irq, IRQ_TYPE_EDGE_RISING); - set_irq_handler(irq, intc_external_irq); - } else { - set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); - set_irq_handler(irq, handle_level_irq); - } + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + irq_desc[irq].chip = &intc_irq_chip; + intc_irq_set_type(irq, 0); } } diff --git a/trunk/arch/m68knommu/platform/527x/Makefile b/trunk/arch/m68knommu/platform/527x/Makefile index 6ac4b57370ea..3d90e6d92459 100644 --- a/trunk/arch/m68knommu/platform/527x/Makefile +++ b/trunk/arch/m68knommu/platform/527x/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/528x/Makefile b/trunk/arch/m68knommu/platform/528x/Makefile index 6ac4b57370ea..3d90e6d92459 100644 --- a/trunk/arch/m68knommu/platform/528x/Makefile +++ b/trunk/arch/m68knommu/platform/528x/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5307/Makefile b/trunk/arch/m68knommu/platform/5307/Makefile index d4293b791f2e..6de526976828 100644 --- a/trunk/arch/m68knommu/platform/5307/Makefile +++ b/trunk/arch/m68knommu/platform/5307/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/532x/Makefile b/trunk/arch/m68knommu/platform/532x/Makefile index ce01669399c6..4cc23245bcd1 100644 --- a/trunk/arch/m68knommu/platform/532x/Makefile +++ b/trunk/arch/m68knommu/platform/532x/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/5407/Makefile b/trunk/arch/m68knommu/platform/5407/Makefile index e83fe148eddc..dee62c5dbaa6 100644 --- a/trunk/arch/m68knommu/platform/5407/Makefile +++ b/trunk/arch/m68knommu/platform/5407/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 diff --git a/trunk/arch/m68knommu/platform/548x/Makefile b/trunk/arch/m68knommu/platform/548x/Makefile deleted file mode 100644 index e6035e7a2d3f..000000000000 --- a/trunk/arch/m68knommu/platform/548x/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for the m68knommu linux kernel. -# - -# -# If you want to play with the HW breakpoints then you will -# need to add define this, which will give you a stack backtrace -# on the console port whenever a DBG interrupt occurs. You have to -# set up you HW breakpoints to trigger a DBG interrupt: -# -# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT -# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT -# - -asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 - -obj-y := config.o - diff --git a/trunk/arch/m68knommu/platform/548x/config.c b/trunk/arch/m68knommu/platform/548x/config.c deleted file mode 100644 index 9888846bd1cf..000000000000 --- a/trunk/arch/m68knommu/platform/548x/config.c +++ /dev/null @@ -1,115 +0,0 @@ -/***************************************************************************/ - -/* - * linux/arch/m68knommu/platform/548x/config.c - * - * Copyright (C) 2010, Philippe De Muyter - */ - -/***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************/ - -static struct mcf_platform_uart m548x_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 64 + 35, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 64 + 34, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE3, - .irq = 64 + 33, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE4, - .irq = 64 + 32, - }, -}; - -static struct platform_device m548x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m548x_uart_platform, -}; - -static struct platform_device *m548x_devices[] __initdata = { - &m548x_uart, -}; - - -/***************************************************************************/ - -static void __init m548x_uart_init_line(int line, int irq) -{ - int rts_cts; - - /* enable io pins */ - switch (line) { - case 0: - rts_cts = 0; break; - case 1: - rts_cts = MCF_PAR_PSC_RTS_RTS; break; - case 2: - rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break; - case 3: - rts_cts = 0; break; - } - __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD, - MCF_MBAR + MCF_PAR_PSC(line)); -} - -static void __init m548x_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m548x_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m548x_uart_init_line(line, m548x_uart_platform[line].irq); -} - -/***************************************************************************/ - -static void mcf548x_reset(void) -{ - /* disable interrupts and enable the watchdog */ - asm("movew #0x2700, %sr\n"); - __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0); - __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0); - __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4), - MCF_MBAR + MCF_GPT_GMS0); -} - -/***************************************************************************/ - -void __init config_BSP(char *commandp, int size) -{ - mach_reset = mcf548x_reset; - m548x_uarts_init(); -} - -/***************************************************************************/ - -static int __init init_BSP(void) -{ - - platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/trunk/arch/m68knommu/platform/68328/entry.S b/trunk/arch/m68knommu/platform/68328/entry.S index 27241e16a526..9d80d2c42866 100644 --- a/trunk/arch/m68knommu/platform/68328/entry.S +++ b/trunk/arch/m68knommu/platform/68328/entry.S @@ -43,10 +43,10 @@ badsys: jra ret_from_exception do_trace: - movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/ + movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/ subql #4,%sp SAVE_SWITCH_STACK - jbsr syscall_trace_enter + jbsr syscall_trace RESTORE_SWITCH_STACK addql #4,%sp movel %sp@(PT_OFF_ORIG_D0),%d1 @@ -57,10 +57,10 @@ do_trace: lea sys_call_table, %a0 jbsr %a0@(%d1) -1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */ +1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */ subql #4,%sp /* dummy return address */ SAVE_SWITCH_STACK - jbsr syscall_trace_leave + jbsr syscall_trace ret_from_signal: RESTORE_SWITCH_STACK @@ -71,16 +71,16 @@ ENTRY(system_call) SAVE_ALL /* save top of frame*/ - pea %sp@ - jbsr set_esp0 - addql #4,%sp + pea %sp@ + jbsr set_esp0 + addql #4,%sp movel %sp@(PT_OFF_ORIG_D0),%d0 movel %sp,%d1 /* get thread_info pointer */ andl #-THREAD_SIZE,%d1 movel %d1,%a2 - btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS) jne do_trace cmpl #NR_syscalls,%d0 jcc badsys @@ -88,10 +88,10 @@ ENTRY(system_call) lea sys_call_table,%a0 movel %a0@(%d0), %a0 jbsr %a0@ - movel %d0,%sp@(PT_OFF_D0) /* save the return value*/ + movel %d0,%sp@(PT_OFF_D0) /* save the return value*/ ret_from_exception: - btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/ + btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/ jeq Luser_return /* if so, skip resched, signals*/ Lkernel_return: @@ -133,7 +133,7 @@ Lreturn: */ inthandler1: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -144,7 +144,7 @@ inthandler1: inthandler2: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -155,7 +155,7 @@ inthandler2: inthandler3: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -166,7 +166,7 @@ inthandler3: inthandler4: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -177,7 +177,7 @@ inthandler4: inthandler5: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -188,7 +188,7 @@ inthandler5: inthandler6: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -199,7 +199,7 @@ inthandler6: inthandler7: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- @@ -210,7 +210,7 @@ inthandler7: inthandler: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and #0x3ff, %d0 movel %sp,%sp@- diff --git a/trunk/arch/m68knommu/platform/68328/head-de2.S b/trunk/arch/m68knommu/platform/68328/head-de2.S index f632fdcb93e9..92d96456d363 100644 --- a/trunk/arch/m68knommu/platform/68328/head-de2.S +++ b/trunk/arch/m68knommu/platform/68328/head-de2.S @@ -1,5 +1,11 @@ +#if defined(CONFIG_RAM32MB) +#define MEM_END 0x02000000 /* Memory size 32Mb */ +#elif defined(CONFIG_RAM16MB) +#define MEM_END 0x01000000 /* Memory size 16Mb */ +#else #define MEM_END 0x00800000 /* Memory size 8Mb */ +#endif #undef CRT_DEBUG diff --git a/trunk/arch/m68knommu/platform/68328/head-ram.S b/trunk/arch/m68knommu/platform/68328/head-ram.S index 7f1aeeacb219..252b80b02038 100644 --- a/trunk/arch/m68knommu/platform/68328/head-ram.S +++ b/trunk/arch/m68knommu/platform/68328/head-ram.S @@ -67,6 +67,33 @@ pclp1: beq pclp1 #endif /* DEBUG */ +#ifdef CONFIG_RELOCATE + /* Copy me to RAM */ + moveal #__rom_start, %a0 + moveal #_stext, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi LD1 + +#ifdef DEBUG + moveq #74, %d7 /* 'J' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp2: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp2 +#endif /* DEBUG */ + /* jump into the RAM copy */ + jmp ram_jump +ram_jump: + +#endif /* CONFIG_RELOCATE */ + #ifdef DEBUG moveq #82, %d7 /* 'R' */ moveb %d7,0xfffff907 /* No absolute addresses */ diff --git a/trunk/arch/m68knommu/platform/68328/ints.c b/trunk/arch/m68knommu/platform/68328/ints.c index 865852806a17..b91ee85d4b5d 100644 --- a/trunk/arch/m68knommu/platform/68328/ints.c +++ b/trunk/arch/m68knommu/platform/68328/ints.c @@ -179,8 +179,10 @@ void __init init_IRQ(void) IMR = ~0; for (i = 0; (i < NR_IRQS); i++) { - set_irq_chip(irq, &intc_irq_chip); - set_irq_handler(irq, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &intc_irq_chip; } } diff --git a/trunk/arch/m68knommu/platform/68360/entry.S b/trunk/arch/m68knommu/platform/68360/entry.S index c131c6e1d92d..6d3460a39cac 100644 --- a/trunk/arch/m68knommu/platform/68360/entry.S +++ b/trunk/arch/m68knommu/platform/68360/entry.S @@ -42,7 +42,7 @@ do_trace: movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/ subql #4,%sp SAVE_SWITCH_STACK - jbsr syscall_trace_enter + jbsr syscall_trace RESTORE_SWITCH_STACK addql #4,%sp movel %sp@(PT_OFF_ORIG_D0),%d1 @@ -56,7 +56,7 @@ do_trace: 1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */ subql #4,%sp /* dummy return address */ SAVE_SWITCH_STACK - jbsr syscall_trace_leave + jbsr syscall_trace ret_from_signal: RESTORE_SWITCH_STACK @@ -71,12 +71,7 @@ ENTRY(system_call) jbsr set_esp0 addql #4,%sp - movel %sp@(PT_OFF_ORIG_D0),%d0 - - movel %sp,%d1 /* get thread_info pointer */ - andl #-THREAD_SIZE,%d1 - movel %d1,%a2 - btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF) jne do_trace cmpl #NR_syscalls,%d0 jcc badsys @@ -129,7 +124,7 @@ Lreturn: */ inthandler: SAVE_ALL - movew %sp@(PT_OFF_FORMATVEC), %d0 + movew %sp@(PT_OFF_VECTOR), %d0 and.l #0x3ff, %d0 lsr.l #0x02, %d0 diff --git a/trunk/arch/m68knommu/platform/68360/ints.c b/trunk/arch/m68knommu/platform/68360/ints.c index ad96ab1051f0..6f22970d8c20 100644 --- a/trunk/arch/m68knommu/platform/68360/ints.c +++ b/trunk/arch/m68knommu/platform/68360/ints.c @@ -132,8 +132,10 @@ void init_IRQ(void) pquicc->intr_cimr = 0x00000000; for (i = 0; (i < NR_IRQS); i++) { - set_irq_chip(irq, &intc_irq_chip); - set_irq_handler(irq, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &intc_irq_chip; } } diff --git a/trunk/arch/m68knommu/platform/68VZ328/config.c b/trunk/arch/m68knommu/platform/68VZ328/config.c index eabaabe8af36..fc5c63054e98 100644 --- a/trunk/arch/m68knommu/platform/68VZ328/config.c +++ b/trunk/arch/m68knommu/platform/68VZ328/config.c @@ -90,6 +90,11 @@ static void init_hardware(char *command, int size) PDIQEG &= ~PD(1); PDIRQEN |= PD(1); /* IRQ enabled */ +#ifdef CONFIG_68328_SERIAL_UART2 + /* Enable RXD TXD port bits to enable UART2 */ + PJSEL &= ~(PJ(5) | PJ(4)); +#endif + #ifdef CONFIG_INIT_LCD /* initialize LCD controller */ LSSA = (long) screen_bits; diff --git a/trunk/arch/m68knommu/platform/coldfire/Makefile b/trunk/arch/m68knommu/platform/coldfire/Makefile index 45f501fa4525..f72a0e5d9996 100644 --- a/trunk/arch/m68knommu/platform/coldfire/Makefile +++ b/trunk/arch/m68knommu/platform/coldfire/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# ccflags-y := -DTRAP_DBG_INTERRUPT -# asflags-y := -DTRAP_DBG_INTERRUPT +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 @@ -26,7 +26,6 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o obj-$(CONFIG_M5307) += timers.o intc.o obj-$(CONFIG_M532x) += timers.o intc-simr.o obj-$(CONFIG_M5407) += timers.o intc.o -obj-$(CONFIG_M548x) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o extra-y := head.o diff --git a/trunk/arch/m68knommu/platform/coldfire/entry.S b/trunk/arch/m68knommu/platform/coldfire/entry.S index 5e92bed94b7e..cd79d7e92ce6 100644 --- a/trunk/arch/m68knommu/platform/coldfire/entry.S +++ b/trunk/arch/m68knommu/platform/coldfire/entry.S @@ -88,7 +88,7 @@ ENTRY(system_call) movel %d2,PT_OFF_D0(%sp) /* on syscall entry */ subql #4,%sp SAVE_SWITCH_STACK - jbsr syscall_trace_enter + jbsr syscall_trace RESTORE_SWITCH_STACK addql #4,%sp movel %d3,%a0 @@ -96,7 +96,7 @@ ENTRY(system_call) movel %d0,%sp@(PT_OFF_D0) /* save the return value */ subql #4,%sp /* dummy return address */ SAVE_SWITCH_STACK - jbsr syscall_trace_leave + jbsr syscall_trace ret_from_signal: RESTORE_SWITCH_STACK diff --git a/trunk/arch/m68knommu/platform/coldfire/intc-2.c b/trunk/arch/m68knommu/platform/coldfire/intc-2.c index 85daa2b3001a..5598c8b8661f 100644 --- a/trunk/arch/m68knommu/platform/coldfire/intc-2.c +++ b/trunk/arch/m68knommu/platform/coldfire/intc-2.c @@ -1,11 +1,5 @@ /* - * intc-2.c - * - * General interrupt controller code for the many ColdFire cores that use - * interrupt controllers with 63 interrupt sources, organized as 56 fully- - * programmable + 7 fixed-level interrupt sources. This includes the 523x - * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such - * controllers, and the 547x and 548x families which have only one of them. + * intc-1.c * * (C) Copyright 2009, Greg Ungerer * @@ -25,37 +19,21 @@ #include /* - * Bit definitions for the ICR family of registers. - */ -#define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ -#define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ - -/* - * Each vector needs a unique priority and level associated with it. + * Each vector needs a unique priority and level asscoiated with it. * We don't really care so much what they are, we don't rely on the - * traditional priority interrupt scheme of the m68k/ColdFire. + * tranditional priority interrupt scheme of the m68k/ColdFire. */ -static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6); - -#ifdef MCFICM_INTC1 -#define NR_VECS 128 -#else -#define NR_VECS 64 -#endif +static u8 intc_intpri = 0x36; static void intc_irq_mask(unsigned int irq) { - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) { + if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) { unsigned long imraddr; u32 val, imrbit; irq -= MCFINT_VECBASE; imraddr = MCF_IPSBAR; -#ifdef MCFICM_INTC1 imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; -#else - imraddr += MCFICM_INTC0; -#endif imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL; imrbit = 0x1 << (irq & 0x1f); @@ -66,17 +44,13 @@ static void intc_irq_mask(unsigned int irq) static void intc_irq_unmask(unsigned int irq) { - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) { + if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) { unsigned long intaddr, imraddr, icraddr; u32 val, imrbit; irq -= MCFINT_VECBASE; intaddr = MCF_IPSBAR; -#ifdef MCFICM_INTC1 intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; -#else - intaddr += MCFICM_INTC0; -#endif imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL); icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f); imrbit = 0x1 << (irq & 0x1f); @@ -93,16 +67,10 @@ static void intc_irq_unmask(unsigned int irq) } } -static int intc_irq_set_type(unsigned int irq, unsigned int type) -{ - return 0; -} - static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, - .set_type = intc_irq_set_type, }; void __init init_IRQ(void) @@ -113,14 +81,13 @@ void __init init_IRQ(void) /* Mask all interrupt sources */ __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL); -#ifdef MCFICM_INTC1 __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL); -#endif for (irq = 0; (irq < NR_IRQS); irq++) { - set_irq_chip(irq, &intc_irq_chip); - set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + irq_desc[irq].chip = &intc_irq_chip; } } diff --git a/trunk/arch/m68knommu/platform/coldfire/intc-simr.c b/trunk/arch/m68knommu/platform/coldfire/intc-simr.c index bb7048636140..1b01e79c2f63 100644 --- a/trunk/arch/m68knommu/platform/coldfire/intc-simr.c +++ b/trunk/arch/m68knommu/platform/coldfire/intc-simr.c @@ -1,8 +1,6 @@ /* * intc-simr.c * - * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts. - * * (C) Copyright 2009, Greg Ungerer * * This file is subject to the terms and conditions of the GNU General Public @@ -70,9 +68,11 @@ void __init init_IRQ(void) __raw_writeb(0xff, MCFINTC1_SIMR); for (irq = 0; (irq < NR_IRQS); irq++) { - set_irq_chip(irq, &intc_irq_chip); - set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + irq_desc[irq].chip = &intc_irq_chip; + intc_irq_set_type(irq, 0); } } diff --git a/trunk/arch/m68knommu/platform/coldfire/intc.c b/trunk/arch/m68knommu/platform/coldfire/intc.c index 60d2fcbe182b..a4560c86db71 100644 --- a/trunk/arch/m68knommu/platform/coldfire/intc.c +++ b/trunk/arch/m68knommu/platform/coldfire/intc.c @@ -143,9 +143,11 @@ void __init init_IRQ(void) mcf_maskimr(0xffffffff); for (irq = 0; (irq < NR_IRQS); irq++) { - set_irq_chip(irq, &intc_irq_chip); - set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = NULL; + irq_desc[irq].depth = 1; + irq_desc[irq].chip = &intc_irq_chip; + intc_irq_set_type(irq, 0); } } diff --git a/trunk/arch/m68knommu/platform/coldfire/sltimers.c b/trunk/arch/m68knommu/platform/coldfire/sltimers.c deleted file mode 100644 index 0a1b937c3e18..000000000000 --- a/trunk/arch/m68knommu/platform/coldfire/sltimers.c +++ /dev/null @@ -1,145 +0,0 @@ -/***************************************************************************/ - -/* - * sltimers.c -- generic ColdFire slice timer support. - * - * Copyright (C) 2009-2010, Philippe De Muyter - * based on - * timers.c -- generic ColdFire hardware timer support. - * Copyright (C) 1999-2008, Greg Ungerer - */ - -/***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************/ - -#ifdef CONFIG_HIGHPROFILE - -/* - * By default use Slice Timer 1 as the profiler clock timer. - */ -#define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a)) - -/* - * Choose a reasonably fast profile timer. Make it an odd value to - * try and get good coverage of kernel operations. - */ -#define PROFILEHZ 1013 - -irqreturn_t mcfslt_profile_tick(int irq, void *dummy) -{ - /* Reset Slice Timer 1 */ - __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR)); - if (current->pid) - profile_tick(CPU_PROFILING); - return IRQ_HANDLED; -} - -static struct irqaction mcfslt_profile_irq = { - .name = "profile timer", - .flags = IRQF_DISABLED | IRQF_TIMER, - .handler = mcfslt_profile_tick, -}; - -void mcfslt_profile_init(void) -{ - printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n", - PROFILEHZ); - - setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq); - - /* Set up TIMER 2 as high speed profile clock */ - __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT)); - __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, - PA(MCFSLT_SCR)); - -} - -#endif /* CONFIG_HIGHPROFILE */ - -/***************************************************************************/ - -/* - * By default use Slice Timer 0 as the system clock timer. - */ -#define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a)) - -static u32 mcfslt_cycles_per_jiffy; -static u32 mcfslt_cnt; - -static irqreturn_t mcfslt_tick(int irq, void *dummy) -{ - /* Reset Slice Timer 0 */ - __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR)); - mcfslt_cnt += mcfslt_cycles_per_jiffy; - return arch_timer_interrupt(irq, dummy); -} - -static struct irqaction mcfslt_timer_irq = { - .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER, - .handler = mcfslt_tick, -}; - -static cycle_t mcfslt_read_clk(struct clocksource *cs) -{ - unsigned long flags; - u32 cycles; - u16 scnt; - - local_irq_save(flags); - scnt = __raw_readl(TA(MCFSLT_SCNT)); - cycles = mcfslt_cnt; - local_irq_restore(flags); - - /* substract because slice timers count down */ - return cycles - scnt; -} - -static struct clocksource mcfslt_clk = { - .name = "slt", - .rating = 250, - .read = mcfslt_read_clk, - .shift = 20, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -void hw_timer_init(void) -{ - mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; - /* - * The coldfire slice timer (SLT) runs from STCNT to 0 included, - * then STCNT again and so on. It counts thus actually - * STCNT + 1 steps for 1 tick, not STCNT. So if you want - * n cycles, initialize STCNT with n - 1. - */ - __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT)); - __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, - TA(MCFSLT_SCR)); - /* initialize mcfslt_cnt knowing that slice timers count down */ - mcfslt_cnt = mcfslt_cycles_per_jiffy; - - setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq); - - mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift); - clocksource_register(&mcfslt_clk); - -#ifdef CONFIG_HIGHPROFILE - mcfslt_profile_init(); -#endif -} diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 784cf822963a..4c9f402295dd 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -2196,14 +2196,10 @@ config TC bool "TURBOchannel support" depends on MACH_DECSTATION help - TURBOchannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS - processors. TURBOchannel programming specifications are available - at: - - and: - - Linux driver support status is documented at: - + TurboChannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS + processors. Documentation on writing device drivers for TurboChannel + is available at: + . #config ACCESSBUS # bool "Access.Bus support" diff --git a/trunk/arch/mips/math-emu/cp1emu.c b/trunk/arch/mips/math-emu/cp1emu.c index ec3faa413f3b..47842b7d26ae 100644 --- a/trunk/arch/mips/math-emu/cp1emu.c +++ b/trunk/arch/mips/math-emu/cp1emu.c @@ -3,6 +3,7 @@ * * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. diff --git a/trunk/arch/mips/math-emu/dp_add.c b/trunk/arch/mips/math-emu/dp_add.c index b422fcad852a..bcf73bb5c33a 100644 --- a/trunk/arch/mips/math-emu/dp_add.c +++ b/trunk/arch/mips/math-emu/dp_add.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_cmp.c b/trunk/arch/mips/math-emu/dp_cmp.c index 0f32486b0ed9..8ab4f320a478 100644 --- a/trunk/arch/mips/math-emu/dp_cmp.c +++ b/trunk/arch/mips/math-emu/dp_cmp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_div.c b/trunk/arch/mips/math-emu/dp_div.c index a1bce1b7c09c..6acedce3b32d 100644 --- a/trunk/arch/mips/math-emu/dp_div.c +++ b/trunk/arch/mips/math-emu/dp_div.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_fint.c b/trunk/arch/mips/math-emu/dp_fint.c index 88571288c9e0..39a71de16f47 100644 --- a/trunk/arch/mips/math-emu/dp_fint.c +++ b/trunk/arch/mips/math-emu/dp_fint.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_flong.c b/trunk/arch/mips/math-emu/dp_flong.c index 14fc01ec742d..f08f223e488a 100644 --- a/trunk/arch/mips/math-emu/dp_flong.c +++ b/trunk/arch/mips/math-emu/dp_flong.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_frexp.c b/trunk/arch/mips/math-emu/dp_frexp.c index cb15a5eaecbb..e650cb10c947 100644 --- a/trunk/arch/mips/math-emu/dp_frexp.c +++ b/trunk/arch/mips/math-emu/dp_frexp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_fsp.c b/trunk/arch/mips/math-emu/dp_fsp.c index 1dfbd92ba9d0..494d19ac7049 100644 --- a/trunk/arch/mips/math-emu/dp_fsp.c +++ b/trunk/arch/mips/math-emu/dp_fsp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_logb.c b/trunk/arch/mips/math-emu/dp_logb.c index 151127e59f5c..603388621ca5 100644 --- a/trunk/arch/mips/math-emu/dp_logb.c +++ b/trunk/arch/mips/math-emu/dp_logb.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_modf.c b/trunk/arch/mips/math-emu/dp_modf.c index b01f9cf6d402..a8570e5c3efc 100644 --- a/trunk/arch/mips/math-emu/dp_modf.c +++ b/trunk/arch/mips/math-emu/dp_modf.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_mul.c b/trunk/arch/mips/math-emu/dp_mul.c index aa566e785f5a..48908a809c17 100644 --- a/trunk/arch/mips/math-emu/dp_mul.c +++ b/trunk/arch/mips/math-emu/dp_mul.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_scalb.c b/trunk/arch/mips/math-emu/dp_scalb.c index 6f5df438dda8..b84e6338330e 100644 --- a/trunk/arch/mips/math-emu/dp_scalb.c +++ b/trunk/arch/mips/math-emu/dp_scalb.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_simple.c b/trunk/arch/mips/math-emu/dp_simple.c index 79ce2673a714..b90974246e5b 100644 --- a/trunk/arch/mips/math-emu/dp_simple.c +++ b/trunk/arch/mips/math-emu/dp_simple.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_sqrt.c b/trunk/arch/mips/math-emu/dp_sqrt.c index a2a51b87ae8f..032328c49888 100644 --- a/trunk/arch/mips/math-emu/dp_sqrt.c +++ b/trunk/arch/mips/math-emu/dp_sqrt.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_sub.c b/trunk/arch/mips/math-emu/dp_sub.c index 0de098cbc77b..a2127d685a0d 100644 --- a/trunk/arch/mips/math-emu/dp_sub.c +++ b/trunk/arch/mips/math-emu/dp_sub.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_tint.c b/trunk/arch/mips/math-emu/dp_tint.c index 0ebe8598b94a..24478623c117 100644 --- a/trunk/arch/mips/math-emu/dp_tint.c +++ b/trunk/arch/mips/math-emu/dp_tint.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/dp_tlong.c b/trunk/arch/mips/math-emu/dp_tlong.c index 133ce2ba0012..0f07ec2be3f9 100644 --- a/trunk/arch/mips/math-emu/dp_tlong.c +++ b/trunk/arch/mips/math-emu/dp_tlong.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754.c b/trunk/arch/mips/math-emu/ieee754.c index 30554e1c67b4..cb1b6822711a 100644 --- a/trunk/arch/mips/math-emu/ieee754.c +++ b/trunk/arch/mips/math-emu/ieee754.c @@ -9,6 +9,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754.h b/trunk/arch/mips/math-emu/ieee754.h index 22796e012060..dd917332792c 100644 --- a/trunk/arch/mips/math-emu/ieee754.h +++ b/trunk/arch/mips/math-emu/ieee754.h @@ -1,6 +1,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as diff --git a/trunk/arch/mips/math-emu/ieee754d.c b/trunk/arch/mips/math-emu/ieee754d.c index 9599bdd32585..a0325337b76c 100644 --- a/trunk/arch/mips/math-emu/ieee754d.c +++ b/trunk/arch/mips/math-emu/ieee754d.c @@ -4,6 +4,7 @@ * MIPS floating point support * * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as diff --git a/trunk/arch/mips/math-emu/ieee754dp.c b/trunk/arch/mips/math-emu/ieee754dp.c index 080b5ca03fc6..2f22fd7fd784 100644 --- a/trunk/arch/mips/math-emu/ieee754dp.c +++ b/trunk/arch/mips/math-emu/ieee754dp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754dp.h b/trunk/arch/mips/math-emu/ieee754dp.h index f139c724c59a..762786538449 100644 --- a/trunk/arch/mips/math-emu/ieee754dp.h +++ b/trunk/arch/mips/math-emu/ieee754dp.h @@ -5,6 +5,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754int.h b/trunk/arch/mips/math-emu/ieee754int.h index 2701d9500959..1a846c5425cd 100644 --- a/trunk/arch/mips/math-emu/ieee754int.h +++ b/trunk/arch/mips/math-emu/ieee754int.h @@ -5,6 +5,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754m.c b/trunk/arch/mips/math-emu/ieee754m.c index 24190f3c9dd6..d66896cd8f21 100644 --- a/trunk/arch/mips/math-emu/ieee754m.c +++ b/trunk/arch/mips/math-emu/ieee754m.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754sp.c b/trunk/arch/mips/math-emu/ieee754sp.c index 271d00d6113a..a19b72185ab9 100644 --- a/trunk/arch/mips/math-emu/ieee754sp.c +++ b/trunk/arch/mips/math-emu/ieee754sp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754sp.h b/trunk/arch/mips/math-emu/ieee754sp.h index 754fd54649b5..d9e3586b5bce 100644 --- a/trunk/arch/mips/math-emu/ieee754sp.h +++ b/trunk/arch/mips/math-emu/ieee754sp.h @@ -5,6 +5,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/ieee754xcpt.c b/trunk/arch/mips/math-emu/ieee754xcpt.c index b99a693c05af..e02423a0ae23 100644 --- a/trunk/arch/mips/math-emu/ieee754xcpt.c +++ b/trunk/arch/mips/math-emu/ieee754xcpt.c @@ -1,6 +1,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_add.c b/trunk/arch/mips/math-emu/sp_add.c index ae1a327ccac0..d8c4211bcfbe 100644 --- a/trunk/arch/mips/math-emu/sp_add.c +++ b/trunk/arch/mips/math-emu/sp_add.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_cmp.c b/trunk/arch/mips/math-emu/sp_cmp.c index 716cf37e2465..d3eff6b04b5a 100644 --- a/trunk/arch/mips/math-emu/sp_cmp.c +++ b/trunk/arch/mips/math-emu/sp_cmp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_div.c b/trunk/arch/mips/math-emu/sp_div.c index d7747928c954..2b437fcfdad9 100644 --- a/trunk/arch/mips/math-emu/sp_div.c +++ b/trunk/arch/mips/math-emu/sp_div.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_fdp.c b/trunk/arch/mips/math-emu/sp_fdp.c index e1515aae0166..4093723d1aa5 100644 --- a/trunk/arch/mips/math-emu/sp_fdp.c +++ b/trunk/arch/mips/math-emu/sp_fdp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_fint.c b/trunk/arch/mips/math-emu/sp_fint.c index 9694d6c016cb..e88e125e01c2 100644 --- a/trunk/arch/mips/math-emu/sp_fint.c +++ b/trunk/arch/mips/math-emu/sp_fint.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_flong.c b/trunk/arch/mips/math-emu/sp_flong.c index 16a651f29865..26d6919a269a 100644 --- a/trunk/arch/mips/math-emu/sp_flong.c +++ b/trunk/arch/mips/math-emu/sp_flong.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_frexp.c b/trunk/arch/mips/math-emu/sp_frexp.c index 5bc993c30044..359c6483dbfa 100644 --- a/trunk/arch/mips/math-emu/sp_frexp.c +++ b/trunk/arch/mips/math-emu/sp_frexp.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_logb.c b/trunk/arch/mips/math-emu/sp_logb.c index 9c14e0c75bd2..3c337219ca32 100644 --- a/trunk/arch/mips/math-emu/sp_logb.c +++ b/trunk/arch/mips/math-emu/sp_logb.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_modf.c b/trunk/arch/mips/math-emu/sp_modf.c index 25a0fbaa0556..76568946b4c0 100644 --- a/trunk/arch/mips/math-emu/sp_modf.c +++ b/trunk/arch/mips/math-emu/sp_modf.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_mul.c b/trunk/arch/mips/math-emu/sp_mul.c index c06bb4022be5..3f070f82212f 100644 --- a/trunk/arch/mips/math-emu/sp_mul.c +++ b/trunk/arch/mips/math-emu/sp_mul.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_scalb.c b/trunk/arch/mips/math-emu/sp_scalb.c index dd76196984c8..44ceb87ea944 100644 --- a/trunk/arch/mips/math-emu/sp_scalb.c +++ b/trunk/arch/mips/math-emu/sp_scalb.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_simple.c b/trunk/arch/mips/math-emu/sp_simple.c index ae4fcfafd853..2fd53c920e99 100644 --- a/trunk/arch/mips/math-emu/sp_simple.c +++ b/trunk/arch/mips/math-emu/sp_simple.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_sqrt.c b/trunk/arch/mips/math-emu/sp_sqrt.c index fed20175f5fb..8a934b9f7eb8 100644 --- a/trunk/arch/mips/math-emu/sp_sqrt.c +++ b/trunk/arch/mips/math-emu/sp_sqrt.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_sub.c b/trunk/arch/mips/math-emu/sp_sub.c index 886ed5bcfefb..dbb802c1a086 100644 --- a/trunk/arch/mips/math-emu/sp_sub.c +++ b/trunk/arch/mips/math-emu/sp_sub.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_tint.c b/trunk/arch/mips/math-emu/sp_tint.c index 0fe9acc7716e..352dc3a5f1af 100644 --- a/trunk/arch/mips/math-emu/sp_tint.c +++ b/trunk/arch/mips/math-emu/sp_tint.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/math-emu/sp_tlong.c b/trunk/arch/mips/math-emu/sp_tlong.c index d0ca6e22be29..92cd9c511a10 100644 --- a/trunk/arch/mips/math-emu/sp_tlong.c +++ b/trunk/arch/mips/math-emu/sp_tlong.c @@ -4,6 +4,7 @@ /* * MIPS floating point support * Copyright (C) 1994-2000 Algorithmics Ltd. + * http://www.algor.co.uk * * ######################################################################## * diff --git a/trunk/arch/mips/pci/fixup-fuloong2e.c b/trunk/arch/mips/pci/fixup-fuloong2e.c index d5d4c018fb04..4f6d8da07f93 100644 --- a/trunk/arch/mips/pci/fixup-fuloong2e.c +++ b/trunk/arch/mips/pci/fixup-fuloong2e.c @@ -52,7 +52,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev) { unsigned int val; - /* Configures port 1, 2, 3, 4 to be validate*/ + /* Configues port 1, 2, 3, 4 to be validate*/ pci_read_config_dword(pdev, 0xe0, &val); pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x4); diff --git a/trunk/arch/mips/sibyte/common/sb_tbprof.c b/trunk/arch/mips/sibyte/common/sb_tbprof.c index 87ccdb4b5ac9..ca35b730d189 100644 --- a/trunk/arch/mips/sibyte/common/sb_tbprof.c +++ b/trunk/arch/mips/sibyte/common/sb_tbprof.c @@ -43,7 +43,7 @@ #include #include #else -#error invalid SiByte UART configuration +#error invalid SiByte UART configuation #endif #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) diff --git a/trunk/arch/powerpc/include/asm/hydra.h b/trunk/arch/powerpc/include/asm/hydra.h index 5b0c98bd46ab..1ad4eed07fbe 100644 --- a/trunk/arch/powerpc/include/asm/hydra.h +++ b/trunk/arch/powerpc/include/asm/hydra.h @@ -10,7 +10,7 @@ * * © Copyright 1995 Apple Computer, Inc. All rights reserved. * - * It's available online from http://www.cpu.lu/~mlan/ftp/MacTech.pdf + * It's available online from http://chrp.apple.com/MacTech.pdf. * You can obtain paper copies of this book from computer bookstores or by * writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San * Francisco, CA 94104. Reference ISBN 1-55860-393-X. diff --git a/trunk/arch/powerpc/include/asm/kvm.h b/trunk/arch/powerpc/include/asm/kvm.h index 18ea6963ad77..6c5547d82bbe 100644 --- a/trunk/arch/powerpc/include/asm/kvm.h +++ b/trunk/arch/powerpc/include/asm/kvm.h @@ -86,6 +86,5 @@ struct kvm_guest_debug_arch { #define KVM_INTERRUPT_SET -1U #define KVM_INTERRUPT_UNSET -2U -#define KVM_INTERRUPT_SET_LEVEL -3U #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/trunk/arch/powerpc/include/asm/kvm_asm.h b/trunk/arch/powerpc/include/asm/kvm_asm.h index 5b7504674397..c5ea4cda34b3 100644 --- a/trunk/arch/powerpc/include/asm/kvm_asm.h +++ b/trunk/arch/powerpc/include/asm/kvm_asm.h @@ -58,7 +58,6 @@ #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 #define BOOK3S_INTERRUPT_EXTERNAL 0x500 -#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501 #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 #define BOOK3S_INTERRUPT_PROGRAM 0x700 #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 @@ -85,8 +84,7 @@ #define BOOK3S_IRQPRIO_EXTERNAL 13 #define BOOK3S_IRQPRIO_DECREMENTER 14 #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15 -#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 16 -#define BOOK3S_IRQPRIO_MAX 17 +#define BOOK3S_IRQPRIO_MAX 16 #define BOOK3S_HFLAG_DCBZ32 0x1 #define BOOK3S_HFLAG_SLB 0x2 diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s.h b/trunk/arch/powerpc/include/asm/kvm_book3s.h index d62e703f1214..8274a2d43925 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s.h @@ -38,6 +38,15 @@ struct kvmppc_slb { bool class : 1; }; +struct kvmppc_sr { + u32 raw; + u32 vsid; + bool Ks : 1; + bool Kp : 1; + bool nx : 1; + bool valid : 1; +}; + struct kvmppc_bat { u64 raw; u32 bepi; @@ -60,13 +69,6 @@ struct kvmppc_sid_map { #define SID_MAP_NUM (1 << SID_MAP_BITS) #define SID_MAP_MASK (SID_MAP_NUM - 1) -#ifdef CONFIG_PPC_BOOK3S_64 -#define SID_CONTEXTS 1 -#else -#define SID_CONTEXTS 128 -#define VSID_POOL_SIZE (SID_CONTEXTS * 16) -#endif - struct kvmppc_vcpu_book3s { struct kvm_vcpu vcpu; struct kvmppc_book3s_shadow_vcpu *shadow_vcpu; @@ -77,22 +79,20 @@ struct kvmppc_vcpu_book3s { u64 vsid; } slb_shadow[64]; u8 slb_shadow_max; + struct kvmppc_sr sr[16]; struct kvmppc_bat ibat[8]; struct kvmppc_bat dbat[8]; u64 hid[6]; u64 gqr[8]; int slb_nr; + u32 dsisr; u64 sdr1; u64 hior; u64 msr_mask; - u64 vsid_next; -#ifdef CONFIG_PPC_BOOK3S_32 - u32 vsid_pool[VSID_POOL_SIZE]; -#else u64 vsid_first; + u64 vsid_next; u64 vsid_max; -#endif - int context_id[SID_CONTEXTS]; + int context_id; ulong prog_flags; /* flags to inject when giving a 700 trap */ }; @@ -131,10 +131,9 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, u32 val); extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu); -extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); -extern ulong kvmppc_trampoline_lowmem; -extern ulong kvmppc_trampoline_enter; +extern u32 kvmppc_trampoline_lowmem; +extern u32 kvmppc_trampoline_enter; extern void kvmppc_rmcall(ulong srr0, ulong srr1); extern void kvmppc_load_up_fpu(void); extern void kvmppc_load_up_altivec(void); diff --git a/trunk/arch/powerpc/include/asm/kvm_host.h b/trunk/arch/powerpc/include/asm/kvm_host.h index bba3b9b72a39..b0b23c007d6e 100644 --- a/trunk/arch/powerpc/include/asm/kvm_host.h +++ b/trunk/arch/powerpc/include/asm/kvm_host.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #define KVM_MAX_VCPUS 1 @@ -42,17 +41,12 @@ #define HPTEG_CACHE_NUM (1 << 15) #define HPTEG_HASH_BITS_PTE 13 -#define HPTEG_HASH_BITS_PTE_LONG 12 #define HPTEG_HASH_BITS_VPTE 13 #define HPTEG_HASH_BITS_VPTE_LONG 5 #define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE) -#define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG) #define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE) #define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG) -/* Physical Address Mask - allowed range of real mode RAM access */ -#define KVM_PAM 0x0fffffffffffffffULL - struct kvm; struct kvm_run; struct kvm_vcpu; @@ -165,10 +159,8 @@ struct kvmppc_mmu { struct hpte_cache { struct hlist_node list_pte; - struct hlist_node list_pte_long; struct hlist_node list_vpte; struct hlist_node list_vpte_long; - struct rcu_head rcu_head; u64 host_va; u64 pfn; ulong slot; @@ -218,20 +210,28 @@ struct kvm_vcpu_arch { u32 cr; #endif + ulong msr; #ifdef CONFIG_PPC_BOOK3S ulong shadow_msr; ulong hflags; ulong guest_owned_ext; #endif u32 mmucr; + ulong sprg0; + ulong sprg1; + ulong sprg2; + ulong sprg3; ulong sprg4; ulong sprg5; ulong sprg6; ulong sprg7; + ulong srr0; + ulong srr1; ulong csrr0; ulong csrr1; ulong dsrr0; ulong dsrr1; + ulong dear; ulong esr; u32 dec; u32 decar; @@ -290,17 +290,12 @@ struct kvm_vcpu_arch { struct tasklet_struct tasklet; u64 dec_jiffies; unsigned long pending_exceptions; - struct kvm_vcpu_arch_shared *shared; - unsigned long magic_page_pa; /* phys addr to map the magic page to */ - unsigned long magic_page_ea; /* effect. addr to map the magic page to */ #ifdef CONFIG_PPC_BOOK3S struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE]; - struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG]; struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE]; struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG]; int hpte_cache_count; - spinlock_t mmu_lock; #endif }; diff --git a/trunk/arch/powerpc/include/asm/kvm_para.h b/trunk/arch/powerpc/include/asm/kvm_para.h index 50533f9adf40..2d48f6a63d0b 100644 --- a/trunk/arch/powerpc/include/asm/kvm_para.h +++ b/trunk/arch/powerpc/include/asm/kvm_para.h @@ -20,153 +20,16 @@ #ifndef __POWERPC_KVM_PARA_H__ #define __POWERPC_KVM_PARA_H__ -#include - -struct kvm_vcpu_arch_shared { - __u64 scratch1; - __u64 scratch2; - __u64 scratch3; - __u64 critical; /* Guest may not get interrupts if == r1 */ - __u64 sprg0; - __u64 sprg1; - __u64 sprg2; - __u64 sprg3; - __u64 srr0; - __u64 srr1; - __u64 dar; - __u64 msr; - __u32 dsisr; - __u32 int_pending; /* Tells the guest if we have an interrupt */ - __u32 sr[16]; -}; - -#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */ -#define HC_VENDOR_KVM (42 << 16) -#define HC_EV_SUCCESS 0 -#define HC_EV_UNIMPLEMENTED 12 - -#define KVM_FEATURE_MAGIC_PAGE 1 - -#define KVM_MAGIC_FEAT_SR (1 << 0) - #ifdef __KERNEL__ -#ifdef CONFIG_KVM_GUEST - -#include - -static inline int kvm_para_available(void) -{ - struct device_node *hyper_node; - - hyper_node = of_find_node_by_path("/hypervisor"); - if (!hyper_node) - return 0; - - if (!of_device_is_compatible(hyper_node, "linux,kvm")) - return 0; - - return 1; -} - -extern unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr); - -#else - static inline int kvm_para_available(void) { return 0; } -static unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr) -{ - return HC_EV_UNIMPLEMENTED; -} - -#endif - -static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2) -{ - unsigned long in[8]; - unsigned long out[8]; - unsigned long r; - - r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM); - *r2 = out[0]; - - return r; -} - -static inline long kvm_hypercall0(unsigned int nr) -{ - unsigned long in[8]; - unsigned long out[8]; - - return kvm_hypercall(in, out, nr | HC_VENDOR_KVM); -} - -static inline long kvm_hypercall1(unsigned int nr, unsigned long p1) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - return kvm_hypercall(in, out, nr | HC_VENDOR_KVM); -} - -static inline long kvm_hypercall2(unsigned int nr, unsigned long p1, - unsigned long p2) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - return kvm_hypercall(in, out, nr | HC_VENDOR_KVM); -} - -static inline long kvm_hypercall3(unsigned int nr, unsigned long p1, - unsigned long p2, unsigned long p3) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - in[2] = p3; - return kvm_hypercall(in, out, nr | HC_VENDOR_KVM); -} - -static inline long kvm_hypercall4(unsigned int nr, unsigned long p1, - unsigned long p2, unsigned long p3, - unsigned long p4) -{ - unsigned long in[8]; - unsigned long out[8]; - - in[0] = p1; - in[1] = p2; - in[2] = p3; - in[3] = p4; - return kvm_hypercall(in, out, nr | HC_VENDOR_KVM); -} - - static inline unsigned int kvm_arch_para_features(void) { - unsigned long r; - - if (!kvm_para_available()) - return 0; - - if(kvm_hypercall0_1(KVM_HC_FEATURES, &r)) - return 0; - - return r; + return 0; } #endif /* __KERNEL__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_ppc.h b/trunk/arch/powerpc/include/asm/kvm_ppc.h index ecb3bc74c344..18d139ec2d22 100644 --- a/trunk/arch/powerpc/include/asm/kvm_ppc.h +++ b/trunk/arch/powerpc/include/asm/kvm_ppc.h @@ -107,7 +107,6 @@ extern int kvmppc_booke_init(void); extern void kvmppc_booke_exit(void); extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu); -extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu); /* * Cuts out inst bits with ordering according to spec. diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile index 36c30f31ec93..4ed076a4db24 100644 --- a/trunk/arch/powerpc/kernel/Makefile +++ b/trunk/arch/powerpc/kernel/Makefile @@ -129,8 +129,6 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),) obj-y += ppc_save_regs.o endif -obj-$(CONFIG_KVM_GUEST) += kvm.o kvm_emul.o - # Disable GCOV in odd or sensitive code GCOV_PROFILE_prom_init.o := n GCOV_PROFILE_ftrace.o := n diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index bd0df2e6aa8f..c3e01945ad4f 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -48,12 +48,12 @@ #ifdef CONFIG_PPC_ISERIES #include #endif -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST) +#ifdef CONFIG_KVM #include -#endif -#if defined(CONFIG_KVM) && defined(CONFIG_PPC_BOOK3S) +#ifndef CONFIG_BOOKE #include #endif +#endif #ifdef CONFIG_PPC32 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) @@ -396,13 +396,12 @@ int main(void) DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); + DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr)); DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4)); DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5)); DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6)); DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid)); - DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared)); - DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); /* book3s */ #ifdef CONFIG_PPC_BOOK3S @@ -467,22 +466,6 @@ int main(void) DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); #endif /* CONFIG_PPC_BOOK3S */ #endif - -#ifdef CONFIG_KVM_GUEST - DEFINE(KVM_MAGIC_SCRATCH1, offsetof(struct kvm_vcpu_arch_shared, - scratch1)); - DEFINE(KVM_MAGIC_SCRATCH2, offsetof(struct kvm_vcpu_arch_shared, - scratch2)); - DEFINE(KVM_MAGIC_SCRATCH3, offsetof(struct kvm_vcpu_arch_shared, - scratch3)); - DEFINE(KVM_MAGIC_INT, offsetof(struct kvm_vcpu_arch_shared, - int_pending)); - DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); - DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared, - critical)); - DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr)); -#endif - #ifdef CONFIG_44x DEFINE(PGD_T_LOG2, PGD_T_LOG2); DEFINE(PTE_T_LOG2, PTE_T_LOG2); diff --git a/trunk/arch/powerpc/kernel/exceptions-64s.S b/trunk/arch/powerpc/kernel/exceptions-64s.S index 9f8b01d6466f..39b0c48872d2 100644 --- a/trunk/arch/powerpc/kernel/exceptions-64s.S +++ b/trunk/arch/powerpc/kernel/exceptions-64s.S @@ -299,12 +299,6 @@ slb_miss_user_pseries: b . /* prevent spec. execution */ #endif /* __DISABLED__ */ -/* KVM's trampoline code needs to be close to the interrupt handlers */ - -#ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#include "../kvm/book3s_rmhandlers.S" -#endif - .align 7 .globl __end_interrupts __end_interrupts: diff --git a/trunk/arch/powerpc/kernel/head_64.S b/trunk/arch/powerpc/kernel/head_64.S index f0dd577e4a5b..c571cd3c1453 100644 --- a/trunk/arch/powerpc/kernel/head_64.S +++ b/trunk/arch/powerpc/kernel/head_64.S @@ -166,6 +166,12 @@ exception_marker: #include "exceptions-64s.S" #endif +/* KVM trampoline code needs to be close to the interrupt handlers */ + +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER +#include "../kvm/book3s_rmhandlers.S" +#endif + _GLOBAL(generic_secondary_thread_init) mr r24,r3 diff --git a/trunk/arch/powerpc/kernel/kvm.c b/trunk/arch/powerpc/kernel/kvm.c deleted file mode 100644 index 428d0e538aec..000000000000 --- a/trunk/arch/powerpc/kernel/kvm.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. - * - * Authors: - * Alexander Graf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define KVM_MAGIC_PAGE (-4096L) -#define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x) - -#define KVM_INST_LWZ 0x80000000 -#define KVM_INST_STW 0x90000000 -#define KVM_INST_LD 0xe8000000 -#define KVM_INST_STD 0xf8000000 -#define KVM_INST_NOP 0x60000000 -#define KVM_INST_B 0x48000000 -#define KVM_INST_B_MASK 0x03ffffff -#define KVM_INST_B_MAX 0x01ffffff - -#define KVM_MASK_RT 0x03e00000 -#define KVM_RT_30 0x03c00000 -#define KVM_MASK_RB 0x0000f800 -#define KVM_INST_MFMSR 0x7c0000a6 -#define KVM_INST_MFSPR_SPRG0 0x7c1042a6 -#define KVM_INST_MFSPR_SPRG1 0x7c1142a6 -#define KVM_INST_MFSPR_SPRG2 0x7c1242a6 -#define KVM_INST_MFSPR_SPRG3 0x7c1342a6 -#define KVM_INST_MFSPR_SRR0 0x7c1a02a6 -#define KVM_INST_MFSPR_SRR1 0x7c1b02a6 -#define KVM_INST_MFSPR_DAR 0x7c1302a6 -#define KVM_INST_MFSPR_DSISR 0x7c1202a6 - -#define KVM_INST_MTSPR_SPRG0 0x7c1043a6 -#define KVM_INST_MTSPR_SPRG1 0x7c1143a6 -#define KVM_INST_MTSPR_SPRG2 0x7c1243a6 -#define KVM_INST_MTSPR_SPRG3 0x7c1343a6 -#define KVM_INST_MTSPR_SRR0 0x7c1a03a6 -#define KVM_INST_MTSPR_SRR1 0x7c1b03a6 -#define KVM_INST_MTSPR_DAR 0x7c1303a6 -#define KVM_INST_MTSPR_DSISR 0x7c1203a6 - -#define KVM_INST_TLBSYNC 0x7c00046c -#define KVM_INST_MTMSRD_L0 0x7c000164 -#define KVM_INST_MTMSRD_L1 0x7c010164 -#define KVM_INST_MTMSR 0x7c000124 - -#define KVM_INST_WRTEEI_0 0x7c000146 -#define KVM_INST_WRTEEI_1 0x7c008146 - -#define KVM_INST_MTSRIN 0x7c0001e4 - -static bool kvm_patching_worked = true; -static char kvm_tmp[1024 * 1024]; -static int kvm_tmp_index; - -static inline void kvm_patch_ins(u32 *inst, u32 new_inst) -{ - *inst = new_inst; - flush_icache_range((ulong)inst, (ulong)inst + 4); -} - -static void kvm_patch_ins_ll(u32 *inst, long addr, u32 rt) -{ -#ifdef CONFIG_64BIT - kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc)); -#else - kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc)); -#endif -} - -static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt) -{ -#ifdef CONFIG_64BIT - kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc)); -#else - kvm_patch_ins(inst, KVM_INST_LWZ | rt | ((addr + 4) & 0x0000fffc)); -#endif -} - -static void kvm_patch_ins_lwz(u32 *inst, long addr, u32 rt) -{ - kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000ffff)); -} - -static void kvm_patch_ins_std(u32 *inst, long addr, u32 rt) -{ -#ifdef CONFIG_64BIT - kvm_patch_ins(inst, KVM_INST_STD | rt | (addr & 0x0000fffc)); -#else - kvm_patch_ins(inst, KVM_INST_STW | rt | ((addr + 4) & 0x0000fffc)); -#endif -} - -static void kvm_patch_ins_stw(u32 *inst, long addr, u32 rt) -{ - kvm_patch_ins(inst, KVM_INST_STW | rt | (addr & 0x0000fffc)); -} - -static void kvm_patch_ins_nop(u32 *inst) -{ - kvm_patch_ins(inst, KVM_INST_NOP); -} - -static void kvm_patch_ins_b(u32 *inst, int addr) -{ -#ifdef CONFIG_RELOCATABLE - /* On relocatable kernels interrupts handlers and our code - can be in different regions, so we don't patch them */ - - extern u32 __end_interrupts; - if ((ulong)inst < (ulong)&__end_interrupts) - return; -#endif - - kvm_patch_ins(inst, KVM_INST_B | (addr & KVM_INST_B_MASK)); -} - -static u32 *kvm_alloc(int len) -{ - u32 *p; - - if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) { - printk(KERN_ERR "KVM: No more space (%d + %d)\n", - kvm_tmp_index, len); - kvm_patching_worked = false; - return NULL; - } - - p = (void*)&kvm_tmp[kvm_tmp_index]; - kvm_tmp_index += len; - - return p; -} - -extern u32 kvm_emulate_mtmsrd_branch_offs; -extern u32 kvm_emulate_mtmsrd_reg_offs; -extern u32 kvm_emulate_mtmsrd_orig_ins_offs; -extern u32 kvm_emulate_mtmsrd_len; -extern u32 kvm_emulate_mtmsrd[]; - -static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt) -{ - u32 *p; - int distance_start; - int distance_end; - ulong next_inst; - - p = kvm_alloc(kvm_emulate_mtmsrd_len * 4); - if (!p) - return; - - /* Find out where we are and put everything there */ - distance_start = (ulong)p - (ulong)inst; - next_inst = ((ulong)inst + 4); - distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs]; - - /* Make sure we only write valid b instructions */ - if (distance_start > KVM_INST_B_MAX) { - kvm_patching_worked = false; - return; - } - - /* Modify the chunk to fit the invocation */ - memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4); - p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK; - switch (get_rt(rt)) { - case 30: - kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs], - magic_var(scratch2), KVM_RT_30); - break; - case 31: - kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs], - magic_var(scratch1), KVM_RT_30); - break; - default: - p[kvm_emulate_mtmsrd_reg_offs] |= rt; - break; - } - - p[kvm_emulate_mtmsrd_orig_ins_offs] = *inst; - flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4); - - /* Patch the invocation */ - kvm_patch_ins_b(inst, distance_start); -} - -extern u32 kvm_emulate_mtmsr_branch_offs; -extern u32 kvm_emulate_mtmsr_reg1_offs; -extern u32 kvm_emulate_mtmsr_reg2_offs; -extern u32 kvm_emulate_mtmsr_orig_ins_offs; -extern u32 kvm_emulate_mtmsr_len; -extern u32 kvm_emulate_mtmsr[]; - -static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt) -{ - u32 *p; - int distance_start; - int distance_end; - ulong next_inst; - - p = kvm_alloc(kvm_emulate_mtmsr_len * 4); - if (!p) - return; - - /* Find out where we are and put everything there */ - distance_start = (ulong)p - (ulong)inst; - next_inst = ((ulong)inst + 4); - distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs]; - - /* Make sure we only write valid b instructions */ - if (distance_start > KVM_INST_B_MAX) { - kvm_patching_worked = false; - return; - } - - /* Modify the chunk to fit the invocation */ - memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4); - p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK; - - /* Make clobbered registers work too */ - switch (get_rt(rt)) { - case 30: - kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs], - magic_var(scratch2), KVM_RT_30); - kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs], - magic_var(scratch2), KVM_RT_30); - break; - case 31: - kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs], - magic_var(scratch1), KVM_RT_30); - kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs], - magic_var(scratch1), KVM_RT_30); - break; - default: - p[kvm_emulate_mtmsr_reg1_offs] |= rt; - p[kvm_emulate_mtmsr_reg2_offs] |= rt; - break; - } - - p[kvm_emulate_mtmsr_orig_ins_offs] = *inst; - flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4); - - /* Patch the invocation */ - kvm_patch_ins_b(inst, distance_start); -} - -#ifdef CONFIG_BOOKE - -extern u32 kvm_emulate_wrteei_branch_offs; -extern u32 kvm_emulate_wrteei_ee_offs; -extern u32 kvm_emulate_wrteei_len; -extern u32 kvm_emulate_wrteei[]; - -static void kvm_patch_ins_wrteei(u32 *inst) -{ - u32 *p; - int distance_start; - int distance_end; - ulong next_inst; - - p = kvm_alloc(kvm_emulate_wrteei_len * 4); - if (!p) - return; - - /* Find out where we are and put everything there */ - distance_start = (ulong)p - (ulong)inst; - next_inst = ((ulong)inst + 4); - distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs]; - - /* Make sure we only write valid b instructions */ - if (distance_start > KVM_INST_B_MAX) { - kvm_patching_worked = false; - return; - } - - /* Modify the chunk to fit the invocation */ - memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4); - p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK; - p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE); - flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4); - - /* Patch the invocation */ - kvm_patch_ins_b(inst, distance_start); -} - -#endif - -#ifdef CONFIG_PPC_BOOK3S_32 - -extern u32 kvm_emulate_mtsrin_branch_offs; -extern u32 kvm_emulate_mtsrin_reg1_offs; -extern u32 kvm_emulate_mtsrin_reg2_offs; -extern u32 kvm_emulate_mtsrin_orig_ins_offs; -extern u32 kvm_emulate_mtsrin_len; -extern u32 kvm_emulate_mtsrin[]; - -static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb) -{ - u32 *p; - int distance_start; - int distance_end; - ulong next_inst; - - p = kvm_alloc(kvm_emulate_mtsrin_len * 4); - if (!p) - return; - - /* Find out where we are and put everything there */ - distance_start = (ulong)p - (ulong)inst; - next_inst = ((ulong)inst + 4); - distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs]; - - /* Make sure we only write valid b instructions */ - if (distance_start > KVM_INST_B_MAX) { - kvm_patching_worked = false; - return; - } - - /* Modify the chunk to fit the invocation */ - memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4); - p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK; - p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10); - p[kvm_emulate_mtsrin_reg2_offs] |= rt; - p[kvm_emulate_mtsrin_orig_ins_offs] = *inst; - flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4); - - /* Patch the invocation */ - kvm_patch_ins_b(inst, distance_start); -} - -#endif - -static void kvm_map_magic_page(void *data) -{ - u32 *features = data; - - ulong in[8]; - ulong out[8]; - - in[0] = KVM_MAGIC_PAGE; - in[1] = KVM_MAGIC_PAGE; - - kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE); - - *features = out[0]; -} - -static void kvm_check_ins(u32 *inst, u32 features) -{ - u32 _inst = *inst; - u32 inst_no_rt = _inst & ~KVM_MASK_RT; - u32 inst_rt = _inst & KVM_MASK_RT; - - switch (inst_no_rt) { - /* Loads */ - case KVM_INST_MFMSR: - kvm_patch_ins_ld(inst, magic_var(msr), inst_rt); - break; - case KVM_INST_MFSPR_SPRG0: - kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt); - break; - case KVM_INST_MFSPR_SPRG1: - kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt); - break; - case KVM_INST_MFSPR_SPRG2: - kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt); - break; - case KVM_INST_MFSPR_SPRG3: - kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt); - break; - case KVM_INST_MFSPR_SRR0: - kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt); - break; - case KVM_INST_MFSPR_SRR1: - kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt); - break; - case KVM_INST_MFSPR_DAR: - kvm_patch_ins_ld(inst, magic_var(dar), inst_rt); - break; - case KVM_INST_MFSPR_DSISR: - kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt); - break; - - /* Stores */ - case KVM_INST_MTSPR_SPRG0: - kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt); - break; - case KVM_INST_MTSPR_SPRG1: - kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt); - break; - case KVM_INST_MTSPR_SPRG2: - kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt); - break; - case KVM_INST_MTSPR_SPRG3: - kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt); - break; - case KVM_INST_MTSPR_SRR0: - kvm_patch_ins_std(inst, magic_var(srr0), inst_rt); - break; - case KVM_INST_MTSPR_SRR1: - kvm_patch_ins_std(inst, magic_var(srr1), inst_rt); - break; - case KVM_INST_MTSPR_DAR: - kvm_patch_ins_std(inst, magic_var(dar), inst_rt); - break; - case KVM_INST_MTSPR_DSISR: - kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt); - break; - - /* Nops */ - case KVM_INST_TLBSYNC: - kvm_patch_ins_nop(inst); - break; - - /* Rewrites */ - case KVM_INST_MTMSRD_L1: - kvm_patch_ins_mtmsrd(inst, inst_rt); - break; - case KVM_INST_MTMSR: - case KVM_INST_MTMSRD_L0: - kvm_patch_ins_mtmsr(inst, inst_rt); - break; - } - - switch (inst_no_rt & ~KVM_MASK_RB) { -#ifdef CONFIG_PPC_BOOK3S_32 - case KVM_INST_MTSRIN: - if (features & KVM_MAGIC_FEAT_SR) { - u32 inst_rb = _inst & KVM_MASK_RB; - kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb); - } - break; - break; -#endif - } - - switch (_inst) { -#ifdef CONFIG_BOOKE - case KVM_INST_WRTEEI_0: - case KVM_INST_WRTEEI_1: - kvm_patch_ins_wrteei(inst); - break; -#endif - } -} - -static void kvm_use_magic_page(void) -{ - u32 *p; - u32 *start, *end; - u32 tmp; - u32 features; - - /* Tell the host to map the magic page to -4096 on all CPUs */ - on_each_cpu(kvm_map_magic_page, &features, 1); - - /* Quick self-test to see if the mapping works */ - if (__get_user(tmp, (u32*)KVM_MAGIC_PAGE)) { - kvm_patching_worked = false; - return; - } - - /* Now loop through all code and find instructions */ - start = (void*)_stext; - end = (void*)_etext; - - for (p = start; p < end; p++) - kvm_check_ins(p, features); - - printk(KERN_INFO "KVM: Live patching for a fast VM %s\n", - kvm_patching_worked ? "worked" : "failed"); -} - -unsigned long kvm_hypercall(unsigned long *in, - unsigned long *out, - unsigned long nr) -{ - unsigned long register r0 asm("r0"); - unsigned long register r3 asm("r3") = in[0]; - unsigned long register r4 asm("r4") = in[1]; - unsigned long register r5 asm("r5") = in[2]; - unsigned long register r6 asm("r6") = in[3]; - unsigned long register r7 asm("r7") = in[4]; - unsigned long register r8 asm("r8") = in[5]; - unsigned long register r9 asm("r9") = in[6]; - unsigned long register r10 asm("r10") = in[7]; - unsigned long register r11 asm("r11") = nr; - unsigned long register r12 asm("r12"); - - asm volatile("bl kvm_hypercall_start" - : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6), - "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11), - "=r"(r12) - : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8), - "r"(r9), "r"(r10), "r"(r11) - : "memory", "cc", "xer", "ctr", "lr"); - - out[0] = r4; - out[1] = r5; - out[2] = r6; - out[3] = r7; - out[4] = r8; - out[5] = r9; - out[6] = r10; - out[7] = r11; - - return r3; -} -EXPORT_SYMBOL_GPL(kvm_hypercall); - -static int kvm_para_setup(void) -{ - extern u32 kvm_hypercall_start; - struct device_node *hyper_node; - u32 *insts; - int len, i; - - hyper_node = of_find_node_by_path("/hypervisor"); - if (!hyper_node) - return -1; - - insts = (u32*)of_get_property(hyper_node, "hcall-instructions", &len); - if (len % 4) - return -1; - if (len > (4 * 4)) - return -1; - - for (i = 0; i < (len / 4); i++) - kvm_patch_ins(&(&kvm_hypercall_start)[i], insts[i]); - - return 0; -} - -static __init void kvm_free_tmp(void) -{ - unsigned long start, end; - - start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK; - end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK; - - /* Free the tmp space we don't need */ - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - init_page_count(virt_to_page(start)); - free_page(start); - totalram_pages++; - } -} - -static int __init kvm_guest_init(void) -{ - if (!kvm_para_available()) - goto free_tmp; - - if (kvm_para_setup()) - goto free_tmp; - - if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE)) - kvm_use_magic_page(); - -#ifdef CONFIG_PPC_BOOK3S_64 - /* Enable napping */ - powersave_nap = 1; -#endif - -free_tmp: - kvm_free_tmp(); - - return 0; -} - -postcore_initcall(kvm_guest_init); diff --git a/trunk/arch/powerpc/kernel/kvm_emul.S b/trunk/arch/powerpc/kernel/kvm_emul.S deleted file mode 100644 index f2b1b2523e61..000000000000 --- a/trunk/arch/powerpc/kernel/kvm_emul.S +++ /dev/null @@ -1,302 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright SUSE Linux Products GmbH 2010 - * - * Authors: Alexander Graf - */ - -#include -#include -#include -#include -#include - -/* Hypercall entry point. Will be patched with device tree instructions. */ - -.global kvm_hypercall_start -kvm_hypercall_start: - li r3, -1 - nop - nop - nop - blr - -#define KVM_MAGIC_PAGE (-4096) - -#ifdef CONFIG_64BIT -#define LL64(reg, offs, reg2) ld reg, (offs)(reg2) -#define STL64(reg, offs, reg2) std reg, (offs)(reg2) -#else -#define LL64(reg, offs, reg2) lwz reg, (offs + 4)(reg2) -#define STL64(reg, offs, reg2) stw reg, (offs + 4)(reg2) -#endif - -#define SCRATCH_SAVE \ - /* Enable critical section. We are critical if \ - shared->critical == r1 */ \ - STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0); \ - \ - /* Save state */ \ - PPC_STL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \ - PPC_STL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \ - mfcr r31; \ - stw r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0); - -#define SCRATCH_RESTORE \ - /* Restore state */ \ - PPC_LL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \ - lwz r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0); \ - mtcr r30; \ - PPC_LL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \ - \ - /* Disable critical section. We are critical if \ - shared->critical == r1 and r2 is always != r1 */ \ - STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0); - -.global kvm_emulate_mtmsrd -kvm_emulate_mtmsrd: - - SCRATCH_SAVE - - /* Put MSR & ~(MSR_EE|MSR_RI) in r31 */ - LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - lis r30, (~(MSR_EE | MSR_RI))@h - ori r30, r30, (~(MSR_EE | MSR_RI))@l - and r31, r31, r30 - - /* OR the register's (MSR_EE|MSR_RI) on MSR */ -kvm_emulate_mtmsrd_reg: - ori r30, r0, 0 - andi. r30, r30, (MSR_EE|MSR_RI) - or r31, r31, r30 - - /* Put MSR back into magic page */ - STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - - /* Check if we have to fetch an interrupt */ - lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0) - cmpwi r31, 0 - beq+ no_check - - /* Check if we may trigger an interrupt */ - andi. r30, r30, MSR_EE - beq no_check - - SCRATCH_RESTORE - - /* Nag hypervisor */ -kvm_emulate_mtmsrd_orig_ins: - tlbsync - - b kvm_emulate_mtmsrd_branch - -no_check: - - SCRATCH_RESTORE - - /* Go back to caller */ -kvm_emulate_mtmsrd_branch: - b . -kvm_emulate_mtmsrd_end: - -.global kvm_emulate_mtmsrd_branch_offs -kvm_emulate_mtmsrd_branch_offs: - .long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4 - -.global kvm_emulate_mtmsrd_reg_offs -kvm_emulate_mtmsrd_reg_offs: - .long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4 - -.global kvm_emulate_mtmsrd_orig_ins_offs -kvm_emulate_mtmsrd_orig_ins_offs: - .long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4 - -.global kvm_emulate_mtmsrd_len -kvm_emulate_mtmsrd_len: - .long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4 - - -#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI) -#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS - -.global kvm_emulate_mtmsr -kvm_emulate_mtmsr: - - SCRATCH_SAVE - - /* Fetch old MSR in r31 */ - LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - - /* Find the changed bits between old and new MSR */ -kvm_emulate_mtmsr_reg1: - ori r30, r0, 0 - xor r31, r30, r31 - - /* Check if we need to really do mtmsr */ - LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS) - and. r31, r31, r30 - - /* No critical bits changed? Maybe we can stay in the guest. */ - beq maybe_stay_in_guest - -do_mtmsr: - - SCRATCH_RESTORE - - /* Just fire off the mtmsr if it's critical */ -kvm_emulate_mtmsr_orig_ins: - mtmsr r0 - - b kvm_emulate_mtmsr_branch - -maybe_stay_in_guest: - - /* Get the target register in r30 */ -kvm_emulate_mtmsr_reg2: - ori r30, r0, 0 - - /* Check if we have to fetch an interrupt */ - lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0) - cmpwi r31, 0 - beq+ no_mtmsr - - /* Check if we may trigger an interrupt */ - andi. r31, r30, MSR_EE - beq no_mtmsr - - b do_mtmsr - -no_mtmsr: - - /* Put MSR into magic page because we don't call mtmsr */ - STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - - SCRATCH_RESTORE - - /* Go back to caller */ -kvm_emulate_mtmsr_branch: - b . -kvm_emulate_mtmsr_end: - -.global kvm_emulate_mtmsr_branch_offs -kvm_emulate_mtmsr_branch_offs: - .long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4 - -.global kvm_emulate_mtmsr_reg1_offs -kvm_emulate_mtmsr_reg1_offs: - .long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4 - -.global kvm_emulate_mtmsr_reg2_offs -kvm_emulate_mtmsr_reg2_offs: - .long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4 - -.global kvm_emulate_mtmsr_orig_ins_offs -kvm_emulate_mtmsr_orig_ins_offs: - .long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4 - -.global kvm_emulate_mtmsr_len -kvm_emulate_mtmsr_len: - .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4 - - - -.global kvm_emulate_wrteei -kvm_emulate_wrteei: - - SCRATCH_SAVE - - /* Fetch old MSR in r31 */ - LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - - /* Remove MSR_EE from old MSR */ - li r30, 0 - ori r30, r30, MSR_EE - andc r31, r31, r30 - - /* OR new MSR_EE onto the old MSR */ -kvm_emulate_wrteei_ee: - ori r31, r31, 0 - - /* Write new MSR value back */ - STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - - SCRATCH_RESTORE - - /* Go back to caller */ -kvm_emulate_wrteei_branch: - b . -kvm_emulate_wrteei_end: - -.global kvm_emulate_wrteei_branch_offs -kvm_emulate_wrteei_branch_offs: - .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4 - -.global kvm_emulate_wrteei_ee_offs -kvm_emulate_wrteei_ee_offs: - .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4 - -.global kvm_emulate_wrteei_len -kvm_emulate_wrteei_len: - .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4 - - -.global kvm_emulate_mtsrin -kvm_emulate_mtsrin: - - SCRATCH_SAVE - - LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0) - andi. r31, r31, MSR_DR | MSR_IR - beq kvm_emulate_mtsrin_reg1 - - SCRATCH_RESTORE - -kvm_emulate_mtsrin_orig_ins: - nop - b kvm_emulate_mtsrin_branch - -kvm_emulate_mtsrin_reg1: - /* rX >> 26 */ - rlwinm r30,r0,6,26,29 - -kvm_emulate_mtsrin_reg2: - stw r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30) - - SCRATCH_RESTORE - - /* Go back to caller */ -kvm_emulate_mtsrin_branch: - b . -kvm_emulate_mtsrin_end: - -.global kvm_emulate_mtsrin_branch_offs -kvm_emulate_mtsrin_branch_offs: - .long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4 - -.global kvm_emulate_mtsrin_reg1_offs -kvm_emulate_mtsrin_reg1_offs: - .long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4 - -.global kvm_emulate_mtsrin_reg2_offs -kvm_emulate_mtsrin_reg2_offs: - .long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4 - -.global kvm_emulate_mtsrin_orig_ins_offs -kvm_emulate_mtsrin_orig_ins_offs: - .long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4 - -.global kvm_emulate_mtsrin_len -kvm_emulate_mtsrin_len: - .long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4 diff --git a/trunk/arch/powerpc/kvm/44x.c b/trunk/arch/powerpc/kvm/44x.c index 74d0e7421143..73c0a3f64ed1 100644 --- a/trunk/arch/powerpc/kvm/44x.c +++ b/trunk/arch/powerpc/kvm/44x.c @@ -43,7 +43,7 @@ int kvmppc_core_check_processor_compat(void) { int r; - if (strncmp(cur_cpu_spec->platform, "ppc440", 6) == 0) + if (strcmp(cur_cpu_spec->platform, "ppc440") == 0) r = 0; else r = -ENOTSUPP; @@ -72,7 +72,6 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) /* Since the guest can directly access the timebase, it must know the * real timebase frequency. Accordingly, it must see the state of * CCR1[TCS]. */ - /* XXX CCR1 doesn't exist on all 440 SoCs. */ vcpu->arch.ccr1 = mfspr(SPRN_CCR1); for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++) @@ -124,14 +123,8 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) if (err) goto free_vcpu; - vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!vcpu->arch.shared) - goto uninit_vcpu; - return vcpu; -uninit_vcpu: - kvm_vcpu_uninit(vcpu); free_vcpu: kmem_cache_free(kvm_vcpu_cache, vcpu_44x); out: @@ -142,7 +135,6 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); - free_page((unsigned long)vcpu->arch.shared); kvm_vcpu_uninit(vcpu); kmem_cache_free(kvm_vcpu_cache, vcpu_44x); } diff --git a/trunk/arch/powerpc/kvm/44x_tlb.c b/trunk/arch/powerpc/kvm/44x_tlb.c index 5f3cff83e089..9b9b5cdea840 100644 --- a/trunk/arch/powerpc/kvm/44x_tlb.c +++ b/trunk/arch/powerpc/kvm/44x_tlb.c @@ -47,7 +47,6 @@ #ifdef DEBUG void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) { - struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); struct kvmppc_44x_tlbe *tlbe; int i; @@ -222,14 +221,14 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index, int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS); + unsigned int as = !!(vcpu->arch.msr & MSR_IS); return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); } int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS); + unsigned int as = !!(vcpu->arch.msr & MSR_DS); return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); } @@ -355,7 +354,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, stlbe.word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf); stlbe.word2 = kvmppc_44x_tlb_shadow_attrib(flags, - vcpu->arch.shared->msr & MSR_PR); + vcpu->arch.msr & MSR_PR); stlbe.tid = !(asid & 0xff); /* Keep track of the reference so we can properly release it later. */ @@ -424,7 +423,7 @@ static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, /* Does it match current guest AS? */ /* XXX what about IS != DS? */ - if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS)) + if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) return 0; gpa = get_tlb_raddr(tlbe); diff --git a/trunk/arch/powerpc/kvm/book3s.c b/trunk/arch/powerpc/kvm/book3s.c index e316847c08c0..a3cef30d1d42 100644 --- a/trunk/arch/powerpc/kvm/book3s.c +++ b/trunk/arch/powerpc/kvm/book3s.c @@ -17,7 +17,6 @@ #include #include #include -#include "trace.h" #include #include @@ -36,6 +35,7 @@ #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU /* #define EXIT_DEBUG */ +/* #define EXIT_DEBUG_SIMPLE */ /* #define DEBUG_EXT */ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, @@ -105,71 +105,65 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) kvmppc_giveup_ext(vcpu, MSR_VSX); } -static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu) +#if defined(EXIT_DEBUG) +static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu) { - ulong smsr = vcpu->arch.shared->msr; + u64 jd = mftb() - vcpu->arch.dec_jiffies; + return vcpu->arch.dec - jd; +} +#endif +static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu) +{ + vcpu->arch.shadow_msr = vcpu->arch.msr; /* Guest MSR values */ - smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE; + vcpu->arch.shadow_msr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | + MSR_BE | MSR_DE; /* Process MSR values */ - smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE; + vcpu->arch.shadow_msr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | + MSR_EE; /* External providers the guest reserved */ - smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext); + vcpu->arch.shadow_msr |= (vcpu->arch.msr & vcpu->arch.guest_owned_ext); /* 64-bit Process MSR values */ #ifdef CONFIG_PPC_BOOK3S_64 - smsr |= MSR_ISF | MSR_HV; + vcpu->arch.shadow_msr |= MSR_ISF | MSR_HV; #endif - vcpu->arch.shadow_msr = smsr; } void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) { - ulong old_msr = vcpu->arch.shared->msr; + ulong old_msr = vcpu->arch.msr; #ifdef EXIT_DEBUG printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr); #endif msr &= to_book3s(vcpu)->msr_mask; - vcpu->arch.shared->msr = msr; + vcpu->arch.msr = msr; kvmppc_recalc_shadow_msr(vcpu); - if (msr & MSR_POW) { + if (msr & (MSR_WE|MSR_POW)) { if (!vcpu->arch.pending_exceptions) { kvm_vcpu_block(vcpu); vcpu->stat.halt_wakeup++; - - /* Unset POW bit after we woke up */ - msr &= ~MSR_POW; - vcpu->arch.shared->msr = msr; } } - if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) != + if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) != (old_msr & (MSR_PR|MSR_IR|MSR_DR))) { kvmppc_mmu_flush_segments(vcpu); kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); - - /* Preload magic page segment when in kernel mode */ - if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) { - struct kvm_vcpu_arch *a = &vcpu->arch; - - if (msr & MSR_DR) - kvmppc_mmu_map_segment(vcpu, a->magic_page_ea); - else - kvmppc_mmu_map_segment(vcpu, a->magic_page_pa); - } } /* Preload FPU if it's enabled */ - if (vcpu->arch.shared->msr & MSR_FP) + if (vcpu->arch.msr & MSR_FP) kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); } void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) { - vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu); - vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags; + vcpu->arch.srr0 = kvmppc_get_pc(vcpu); + vcpu->arch.srr1 = vcpu->arch.msr | flags; kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec); vcpu->arch.mmu.reset_msr(vcpu); } @@ -186,7 +180,6 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec) case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; - case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL; break; case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; @@ -206,9 +199,6 @@ static void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, { clear_bit(kvmppc_book3s_vec2irqprio(vec), &vcpu->arch.pending_exceptions); - - if (!vcpu->arch.pending_exceptions) - vcpu->arch.shared->int_pending = 0; } void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) @@ -247,19 +237,13 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL; - - if (irq->irq == KVM_INTERRUPT_SET_LEVEL) - vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL; - - kvmppc_book3s_queue_irqprio(vcpu, vec); + kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); } void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); - kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL); } int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) @@ -267,29 +251,14 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) int deliver = 1; int vec = 0; ulong flags = 0ULL; - ulong crit_raw = vcpu->arch.shared->critical; - ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); - bool crit; - - /* Truncate crit indicators in 32 bit mode */ - if (!(vcpu->arch.shared->msr & MSR_SF)) { - crit_raw &= 0xffffffff; - crit_r1 &= 0xffffffff; - } - - /* Critical section when crit == r1 */ - crit = (crit_raw == crit_r1); - /* ... and we're in supervisor mode */ - crit = crit && !(vcpu->arch.shared->msr & MSR_PR); switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: - deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; + deliver = vcpu->arch.msr & MSR_EE; vec = BOOK3S_INTERRUPT_DECREMENTER; break; case BOOK3S_IRQPRIO_EXTERNAL: - case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: - deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; + deliver = vcpu->arch.msr & MSR_EE; vec = BOOK3S_INTERRUPT_EXTERNAL; break; case BOOK3S_IRQPRIO_SYSTEM_RESET: @@ -351,27 +320,9 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) return deliver; } -/* - * This function determines if an irqprio should be cleared once issued. - */ -static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority) -{ - switch (priority) { - case BOOK3S_IRQPRIO_DECREMENTER: - /* DEC interrupts get cleared by mtdec */ - return false; - case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: - /* External interrupts get cleared by userspace */ - return false; - } - - return true; -} - void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) { unsigned long *pending = &vcpu->arch.pending_exceptions; - unsigned long old_pending = vcpu->arch.pending_exceptions; unsigned int priority; #ifdef EXIT_DEBUG @@ -381,7 +332,8 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) priority = __ffs(*pending); while (priority < BOOK3S_IRQPRIO_MAX) { if (kvmppc_book3s_irqprio_deliver(vcpu, priority) && - clear_irqprio(vcpu, priority)) { + (priority != BOOK3S_IRQPRIO_DECREMENTER)) { + /* DEC interrupts get cleared by mtdec */ clear_bit(priority, &vcpu->arch.pending_exceptions); break; } @@ -390,12 +342,6 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) BITS_PER_BYTE * sizeof(*pending), priority + 1); } - - /* Tell the guest about our interrupt status */ - if (*pending) - vcpu->arch.shared->int_pending = 1; - else if (old_pending) - vcpu->arch.shared->int_pending = 0; } void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) @@ -452,25 +398,6 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) } } -pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - ulong mp_pa = vcpu->arch.magic_page_pa; - - /* Magic page override */ - if (unlikely(mp_pa) && - unlikely(((gfn << PAGE_SHIFT) & KVM_PAM) == - ((mp_pa & PAGE_MASK) & KVM_PAM))) { - ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK; - pfn_t pfn; - - pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT; - get_page(pfn_to_page(pfn)); - return pfn; - } - - return gfn_to_pfn(vcpu->kvm, gfn); -} - /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to * emulate 32 bytes dcbz length. @@ -488,10 +415,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) int i; hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) { - kvm_release_page_clean(hpage); + if (is_error_page(hpage)) return; - } hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; @@ -512,14 +437,14 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, struct kvmppc_pte *pte) { - int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR)); + int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR)); int r; if (relocated) { r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data); } else { pte->eaddr = eaddr; - pte->raddr = eaddr & KVM_PAM; + pte->raddr = eaddr & 0xffffffff; pte->vpage = VSID_REAL | eaddr >> 12; pte->may_read = true; pte->may_write = true; @@ -608,13 +533,6 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) { - ulong mp_pa = vcpu->arch.magic_page_pa; - - if (unlikely(mp_pa) && - unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) { - return 1; - } - return kvm_is_visible_gfn(vcpu->kvm, gfn); } @@ -627,8 +545,8 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, int page_found = 0; struct kvmppc_pte pte; bool is_mmio = false; - bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false; - bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false; + bool dr = (vcpu->arch.msr & MSR_DR) ? true : false; + bool ir = (vcpu->arch.msr & MSR_IR) ? true : false; u64 vsid; relocated = data ? dr : ir; @@ -640,12 +558,12 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, pte.may_execute = true; pte.may_read = true; pte.may_write = true; - pte.raddr = eaddr & KVM_PAM; + pte.raddr = eaddr & 0xffffffff; pte.eaddr = eaddr; pte.vpage = eaddr >> 12; } - switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { + switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { case 0: pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12)); break; @@ -653,7 +571,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, case MSR_IR: vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); - if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR) + if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR) pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12)); else pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12)); @@ -676,23 +594,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, if (page_found == -ENOENT) { /* Page not found in guest PTE entries */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; - vcpu->arch.shared->msr |= - (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); + vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); + to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr; + vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); kvmppc_book3s_queue_irqprio(vcpu, vec); } else if (page_found == -EPERM) { /* Storage protection */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); - vcpu->arch.shared->dsisr = - to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE; - vcpu->arch.shared->dsisr |= DSISR_PROTFAULT; - vcpu->arch.shared->msr |= - (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); + vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); + to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE; + to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT; + vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); kvmppc_book3s_queue_irqprio(vcpu, vec); } else if (page_found == -EINVAL) { /* Page not found in guest SLB */ - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); } else if (!is_mmio && kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { @@ -780,11 +695,9 @@ static int kvmppc_read_inst(struct kvm_vcpu *vcpu) ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); if (ret == -ENOENT) { - ulong msr = vcpu->arch.shared->msr; - - msr = kvmppc_set_field(msr, 33, 33, 1); - msr = kvmppc_set_field(msr, 34, 36, 0); - vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0); + vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1); + vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0); + vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0); kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE); return EMULATE_AGAIN; } @@ -823,7 +736,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) return RESUME_GUEST; - if (!(vcpu->arch.shared->msr & msr)) { + if (!(vcpu->arch.msr & msr)) { kvmppc_book3s_queue_irqprio(vcpu, exit_nr); return RESUME_GUEST; } @@ -883,8 +796,16 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, run->exit_reason = KVM_EXIT_UNKNOWN; run->ready_for_interrupt_injection = 1; - - trace_kvm_book3s_exit(exit_nr, vcpu); +#ifdef EXIT_DEBUG + printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n", + exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu), + kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1); +#elif defined (EXIT_DEBUG_SIMPLE) + if ((exit_nr != 0x900) && (exit_nr != 0x500)) + printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n", + exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu), + vcpu->arch.msr); +#endif kvm_resched(vcpu); switch (exit_nr) { case BOOK3S_INTERRUPT_INST_STORAGE: @@ -915,9 +836,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); r = RESUME_GUEST; } else { - vcpu->arch.shared->msr |= - to_svcpu(vcpu)->shadow_srr1 & 0x58000000; + vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000; kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); r = RESUME_GUEST; } break; @@ -940,16 +861,17 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) { r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); } else { - vcpu->arch.shared->dar = dar; - vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr; + vcpu->arch.dear = dar; + to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr; kvmppc_book3s_queue_irqprio(vcpu, exit_nr); + kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL); r = RESUME_GUEST; } break; } case BOOK3S_INTERRUPT_DATA_SEGMENT: if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) { - vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); + vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_SEGMENT); } @@ -982,7 +904,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, program_interrupt: flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull; - if (vcpu->arch.shared->msr & MSR_PR) { + if (vcpu->arch.msr & MSR_PR) { #ifdef EXIT_DEBUG printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); #endif @@ -1019,10 +941,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, break; } case BOOK3S_INTERRUPT_SYSCALL: + // XXX make user settable if (vcpu->arch.osi_enabled && (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { - /* MOL hypercalls */ u64 *gprs = run->osi.gprs; int i; @@ -1031,13 +953,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, gprs[i] = kvmppc_get_gpr(vcpu, i); vcpu->arch.osi_needed = 1; r = RESUME_HOST_NV; - } else if (!(vcpu->arch.shared->msr & MSR_PR) && - (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { - /* KVM PV hypercalls */ - kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); - r = RESUME_GUEST; + } else { - /* Guest syscalls */ vcpu->stat.syscall_exits++; kvmppc_book3s_queue_irqprio(vcpu, exit_nr); r = RESUME_GUEST; @@ -1072,9 +989,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, } case BOOK3S_INTERRUPT_ALIGNMENT: if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { - vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu, + to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu, kvmppc_get_last_inst(vcpu)); - vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu, + vcpu->arch.dear = kvmppc_alignment_dar(vcpu, kvmppc_get_last_inst(vcpu)); kvmppc_book3s_queue_irqprio(vcpu, exit_nr); } @@ -1114,7 +1031,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, } } - trace_kvm_book3s_reenter(r, vcpu); +#ifdef EXIT_DEBUG + printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r); +#endif return r; } @@ -1133,14 +1052,14 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) regs->ctr = kvmppc_get_ctr(vcpu); regs->lr = kvmppc_get_lr(vcpu); regs->xer = kvmppc_get_xer(vcpu); - regs->msr = vcpu->arch.shared->msr; - regs->srr0 = vcpu->arch.shared->srr0; - regs->srr1 = vcpu->arch.shared->srr1; + regs->msr = vcpu->arch.msr; + regs->srr0 = vcpu->arch.srr0; + regs->srr1 = vcpu->arch.srr1; regs->pid = vcpu->arch.pid; - regs->sprg0 = vcpu->arch.shared->sprg0; - regs->sprg1 = vcpu->arch.shared->sprg1; - regs->sprg2 = vcpu->arch.shared->sprg2; - regs->sprg3 = vcpu->arch.shared->sprg3; + regs->sprg0 = vcpu->arch.sprg0; + regs->sprg1 = vcpu->arch.sprg1; + regs->sprg2 = vcpu->arch.sprg2; + regs->sprg3 = vcpu->arch.sprg3; regs->sprg5 = vcpu->arch.sprg4; regs->sprg6 = vcpu->arch.sprg5; regs->sprg7 = vcpu->arch.sprg6; @@ -1161,12 +1080,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) kvmppc_set_lr(vcpu, regs->lr); kvmppc_set_xer(vcpu, regs->xer); kvmppc_set_msr(vcpu, regs->msr); - vcpu->arch.shared->srr0 = regs->srr0; - vcpu->arch.shared->srr1 = regs->srr1; - vcpu->arch.shared->sprg0 = regs->sprg0; - vcpu->arch.shared->sprg1 = regs->sprg1; - vcpu->arch.shared->sprg2 = regs->sprg2; - vcpu->arch.shared->sprg3 = regs->sprg3; + vcpu->arch.srr0 = regs->srr0; + vcpu->arch.srr1 = regs->srr1; + vcpu->arch.sprg0 = regs->sprg0; + vcpu->arch.sprg1 = regs->sprg1; + vcpu->arch.sprg2 = regs->sprg2; + vcpu->arch.sprg3 = regs->sprg3; vcpu->arch.sprg5 = regs->sprg4; vcpu->arch.sprg6 = regs->sprg5; vcpu->arch.sprg7 = regs->sprg6; @@ -1192,9 +1111,10 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv; } } else { - for (i = 0; i < 16; i++) - sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i]; - + for (i = 0; i < 16; i++) { + sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw; + sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw; + } for (i = 0; i < 8; i++) { sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw; sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw; @@ -1305,7 +1225,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) struct kvmppc_vcpu_book3s *vcpu_book3s; struct kvm_vcpu *vcpu; int err = -ENOMEM; - unsigned long p; vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s)); if (!vcpu_book3s) @@ -1323,12 +1242,6 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) if (err) goto free_shadow_vcpu; - p = __get_free_page(GFP_KERNEL|__GFP_ZERO); - /* the real shared page fills the last 4k of our page */ - vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096); - if (!p) - goto uninit_vcpu; - vcpu->arch.host_retip = kvm_return_point; vcpu->arch.host_msr = mfmsr(); #ifdef CONFIG_PPC_BOOK3S_64 @@ -1355,12 +1268,10 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) err = kvmppc_mmu_init(vcpu); if (err < 0) - goto uninit_vcpu; + goto free_shadow_vcpu; return vcpu; -uninit_vcpu: - kvm_vcpu_uninit(vcpu); free_shadow_vcpu: kfree(vcpu_book3s->shadow_vcpu); free_vcpu: @@ -1373,7 +1284,6 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); - free_page((unsigned long)vcpu->arch.shared & PAGE_MASK); kvm_vcpu_uninit(vcpu); kfree(vcpu_book3s->shadow_vcpu); vfree(vcpu_book3s); @@ -1436,7 +1346,7 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) local_irq_enable(); /* Preload FPU if it's enabled */ - if (vcpu->arch.shared->msr & MSR_FP) + if (vcpu->arch.msr & MSR_FP) kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); ret = __kvmppc_vcpu_entry(kvm_run, vcpu); diff --git a/trunk/arch/powerpc/kvm/book3s_32_mmu.c b/trunk/arch/powerpc/kvm/book3s_32_mmu.c index c8cefdd15fd8..3292d76101d2 100644 --- a/trunk/arch/powerpc/kvm/book3s_32_mmu.c +++ b/trunk/arch/powerpc/kvm/book3s_32_mmu.c @@ -58,39 +58,14 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu) #endif } -static inline u32 sr_vsid(u32 sr_raw) -{ - return sr_raw & 0x0fffffff; -} - -static inline bool sr_valid(u32 sr_raw) -{ - return (sr_raw & 0x80000000) ? false : true; -} - -static inline bool sr_ks(u32 sr_raw) -{ - return (sr_raw & 0x40000000) ? true: false; -} - -static inline bool sr_kp(u32 sr_raw) -{ - return (sr_raw & 0x20000000) ? true: false; -} - -static inline bool sr_nx(u32 sr_raw) -{ - return (sr_raw & 0x10000000) ? true: false; -} - static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data); static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid); -static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr) +static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) { - return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf]; + return &vcpu_book3s->sr[(eaddr >> 28) & 0xf]; } static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, @@ -112,7 +87,7 @@ static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) } static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, - u32 sre, gva_t eaddr, + struct kvmppc_sr *sre, gva_t eaddr, bool primary) { u32 page, hash, pteg, htabmask; @@ -121,7 +96,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 page = (eaddr & 0x0FFFFFFF) >> 12; htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; - hash = ((sr_vsid(sre) ^ page) << 6); + hash = ((sre->vsid ^ page) << 6); if (!primary) hash = ~hash; hash &= htabmask; @@ -129,8 +104,8 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", - kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg, - sr_vsid(sre)); + vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg, + sre->vsid); r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); if (kvm_is_error_hva(r)) @@ -138,9 +113,10 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3 return r | (pteg & ~PAGE_MASK); } -static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary) +static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr, + bool primary) { - return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) | + return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) | (primary ? 0 : 0x40) | 0x80000000; } @@ -157,7 +133,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, else bat = &vcpu_book3s->ibat[i]; - if (vcpu->arch.shared->msr & MSR_PR) { + if (vcpu->arch.msr & MSR_PR) { if (!bat->vp) continue; } else { @@ -204,17 +180,17 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, bool primary) { struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); - u32 sre; + struct kvmppc_sr *sre; hva_t ptegp; u32 pteg[16]; u32 ptem = 0; int i; int found = 0; - sre = find_sr(vcpu, eaddr); + sre = find_sr(vcpu_book3s, eaddr); dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, - sr_vsid(sre), sre); + sre->vsid, sre->raw); pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); @@ -238,8 +214,8 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); pp = pteg[i+1] & 3; - if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) || - (sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR))) + if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) || + (sre->Ks && !(vcpu->arch.msr & MSR_PR))) pp |= 4; pte->may_write = false; @@ -293,7 +269,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", to_book3s(vcpu)->sdr1, ptegp); for (i=0; i<16; i+=2) { - dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n", + dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n", i, pteg[i], pteg[i+1], ptem); } } @@ -305,24 +281,8 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data) { int r; - ulong mp_ea = vcpu->arch.magic_page_ea; pte->eaddr = eaddr; - - /* Magic page override */ - if (unlikely(mp_ea) && - unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) && - !(vcpu->arch.shared->msr & MSR_PR)) { - pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); - pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff); - pte->raddr &= KVM_PAM; - pte->may_execute = true; - pte->may_read = true; - pte->may_write = true; - - return 0; - } - r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); if (r < 0) r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); @@ -335,13 +295,30 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) { - return vcpu->arch.shared->sr[srnum]; + return to_book3s(vcpu)->sr[srnum].raw; } static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, ulong value) { - vcpu->arch.shared->sr[srnum] = value; + struct kvmppc_sr *sre; + + sre = &to_book3s(vcpu)->sr[srnum]; + + /* Flush any left-over shadows from the previous SR */ + + /* XXX Not necessary? */ + /* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */ + + /* And then put in the new SR */ + sre->raw = value; + sre->vsid = (value & 0x0fffffff); + sre->valid = (value & 0x80000000) ? false : true; + sre->Ks = (value & 0x40000000) ? true : false; + sre->Kp = (value & 0x20000000) ? true : false; + sre->nx = (value & 0x10000000) ? true : false; + + /* Map the new segment */ kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); } @@ -354,19 +331,19 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid) { ulong ea = esid << SID_SHIFT; - u32 sr; + struct kvmppc_sr *sr; u64 gvsid = esid; - if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { - sr = find_sr(vcpu, ea); - if (sr_valid(sr)) - gvsid = sr_vsid(sr); + if (vcpu->arch.msr & (MSR_DR|MSR_IR)) { + sr = find_sr(to_book3s(vcpu), ea); + if (sr->valid) + gvsid = sr->vsid; } /* In case we only have one of MSR_IR or MSR_DR set, let's put that in the real-mode context (and hope RM doesn't access high memory) */ - switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { + switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { case 0: *vsid = VSID_REAL | esid; break; @@ -377,8 +354,8 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, *vsid = VSID_REAL_DR | gvsid; break; case MSR_DR|MSR_IR: - if (sr_valid(sr)) - *vsid = sr_vsid(sr); + if (sr->valid) + *vsid = sr->vsid; else *vsid = VSID_BAT | gvsid; break; @@ -386,7 +363,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, BUG(); } - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) *vsid |= VSID_PR; return 0; diff --git a/trunk/arch/powerpc/kvm/book3s_32_mmu_host.c b/trunk/arch/powerpc/kvm/book3s_32_mmu_host.c index 9fecbfbce773..0b51ef872c1e 100644 --- a/trunk/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/trunk/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -76,14 +77,7 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) * a hash, so we don't waste cycles on looping */ static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid) { - return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK)); + return hash_64(gvsid, SID_MAP_BITS); } @@ -92,7 +86,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) struct kvmppc_sid_map *map; u16 sid_map_mask; - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) gvsid |= VSID_PR; sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); @@ -153,8 +147,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) struct hpte_cache *pte; /* Get host physical address for gpa */ - hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT); - if (is_error_pfn(hpaddr)) { + hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); + if (kvm_is_error_hva(hpaddr)) { printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr); return -EINVAL; @@ -259,7 +253,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) u16 sid_map_mask; static int backwards_map = 0; - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) gvsid |= VSID_PR; /* We might get collisions that trap in preceding order, so let's @@ -275,15 +269,18 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) backwards_map = !backwards_map; /* Uh-oh ... out of mappings. Let's flush! */ - if (vcpu_book3s->vsid_next >= VSID_POOL_SIZE) { - vcpu_book3s->vsid_next = 0; + if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) { + vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; memset(vcpu_book3s->sid_map, 0, sizeof(struct kvmppc_sid_map) * SID_MAP_NUM); kvmppc_mmu_pte_flush(vcpu, 0, 0); kvmppc_mmu_flush_segments(vcpu); } - map->host_vsid = vcpu_book3s->vsid_pool[vcpu_book3s->vsid_next]; - vcpu_book3s->vsid_next++; + map->host_vsid = vcpu_book3s->vsid_next; + + /* Would have to be 111 to be completely aligned with the rest of + Linux, but that is just way too little space! */ + vcpu_book3s->vsid_next+=1; map->guest_vsid = gvsid; map->valid = true; @@ -330,38 +327,40 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) { - int i; - kvmppc_mmu_hpte_destroy(vcpu); preempt_disable(); - for (i = 0; i < SID_CONTEXTS; i++) - __destroy_context(to_book3s(vcpu)->context_id[i]); + __destroy_context(to_book3s(vcpu)->context_id); preempt_enable(); } /* From mm/mmu_context_hash32.c */ -#define CTX_TO_VSID(c, id) ((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff) +#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff) int kvmppc_mmu_init(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); int err; ulong sdr1; - int i; - int j; - for (i = 0; i < SID_CONTEXTS; i++) { - err = __init_new_context(); - if (err < 0) - goto init_fail; - vcpu3s->context_id[i] = err; + err = __init_new_context(); + if (err < 0) + return -1; + vcpu3s->context_id = err; - /* Remember context id for this combination */ - for (j = 0; j < 16; j++) - vcpu3s->vsid_pool[(i * 16) + j] = CTX_TO_VSID(err, j); - } + vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1; + vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id); + +#if 0 /* XXX still doesn't guarantee uniqueness */ + /* We could collide with the Linux vsid space because the vsid + * wraps around at 24 bits. We're safe if we do our own space + * though, so let's always set the highest bit. */ - vcpu3s->vsid_next = 0; + vcpu3s->vsid_max |= 0x00800000; + vcpu3s->vsid_first |= 0x00800000; +#endif + BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first); + + vcpu3s->vsid_next = vcpu3s->vsid_first; /* Remember where the HTAB is */ asm ( "mfsdr1 %0" : "=r"(sdr1) ); @@ -371,14 +370,4 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu) kvmppc_mmu_hpte_init(vcpu); return 0; - -init_fail: - for (j = 0; j < i; j++) { - if (!vcpu3s->context_id[j]) - continue; - - __destroy_context(to_book3s(vcpu)->context_id[j]); - } - - return -1; } diff --git a/trunk/arch/powerpc/kvm/book3s_64_mmu.c b/trunk/arch/powerpc/kvm/book3s_64_mmu.c index d7889ef3211e..4025ea26b3c1 100644 --- a/trunk/arch/powerpc/kvm/book3s_64_mmu.c +++ b/trunk/arch/powerpc/kvm/book3s_64_mmu.c @@ -163,22 +163,6 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, bool found = false; bool perm_err = false; int second = 0; - ulong mp_ea = vcpu->arch.magic_page_ea; - - /* Magic page override */ - if (unlikely(mp_ea) && - unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) && - !(vcpu->arch.shared->msr & MSR_PR)) { - gpte->eaddr = eaddr; - gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data); - gpte->raddr = vcpu->arch.magic_page_pa | (gpte->raddr & 0xfff); - gpte->raddr &= KVM_PAM; - gpte->may_execute = true; - gpte->may_read = true; - gpte->may_write = true; - - return 0; - } slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr); if (!slbe) @@ -196,9 +180,9 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, goto no_page_found; } - if ((vcpu->arch.shared->msr & MSR_PR) && slbe->Kp) + if ((vcpu->arch.msr & MSR_PR) && slbe->Kp) key = 4; - else if (!(vcpu->arch.shared->msr & MSR_PR) && slbe->Ks) + else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks) key = 4; for (i=0; i<16; i+=2) { @@ -397,7 +381,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu) for (i = 1; i < vcpu_book3s->slb_nr; i++) vcpu_book3s->slb[i].valid = false; - if (vcpu->arch.shared->msr & MSR_IR) { + if (vcpu->arch.msr & MSR_IR) { kvmppc_mmu_flush_segments(vcpu); kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); } @@ -461,15 +445,14 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, ulong ea = esid << SID_SHIFT; struct kvmppc_slb *slb; u64 gvsid = esid; - ulong mp_ea = vcpu->arch.magic_page_ea; - if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { + if (vcpu->arch.msr & (MSR_DR|MSR_IR)) { slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea); if (slb) gvsid = slb->vsid; } - switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { + switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { case 0: *vsid = VSID_REAL | esid; break; @@ -481,7 +464,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, break; case MSR_DR|MSR_IR: if (!slb) - goto no_slb; + return -ENOENT; *vsid = gvsid; break; @@ -490,21 +473,10 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, break; } - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) *vsid |= VSID_PR; return 0; - -no_slb: - /* Catch magic page case */ - if (unlikely(mp_ea) && - unlikely(esid == (mp_ea >> SID_SHIFT)) && - !(vcpu->arch.shared->msr & MSR_PR)) { - *vsid = VSID_REAL | esid; - return 0; - } - - return -EINVAL; } static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu) diff --git a/trunk/arch/powerpc/kvm/book3s_64_mmu_host.c b/trunk/arch/powerpc/kvm/book3s_64_mmu_host.c index fa2f08434ba5..384179a5002b 100644 --- a/trunk/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/trunk/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -27,9 +28,24 @@ #include #include #include -#include "trace.h" #define PTE_SIZE 12 +#define VSID_ALL 0 + +/* #define DEBUG_MMU */ +/* #define DEBUG_SLB */ + +#ifdef DEBUG_MMU +#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__) +#else +#define dprintk_mmu(a, ...) do { } while(0) +#endif + +#ifdef DEBUG_SLB +#define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__) +#else +#define dprintk_slb(a, ...) do { } while(0) +#endif void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { @@ -42,39 +58,34 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) * a hash, so we don't waste cycles on looping */ static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid) { - return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^ - ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK)); + return hash_64(gvsid, SID_MAP_BITS); } - static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) { struct kvmppc_sid_map *map; u16 sid_map_mask; - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) gvsid |= VSID_PR; sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); map = &to_book3s(vcpu)->sid_map[sid_map_mask]; - if (map->valid && (map->guest_vsid == gvsid)) { - trace_kvm_book3s_slb_found(gvsid, map->host_vsid); + if (map->guest_vsid == gvsid) { + dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n", + gvsid, map->host_vsid); return map; } map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask]; - if (map->valid && (map->guest_vsid == gvsid)) { - trace_kvm_book3s_slb_found(gvsid, map->host_vsid); + if (map->guest_vsid == gvsid) { + dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", + gvsid, map->host_vsid); return map; } - trace_kvm_book3s_slb_fail(sid_map_mask, gvsid); + dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n", + sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid); return NULL; } @@ -90,13 +101,18 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) struct kvmppc_sid_map *map; /* Get host physical address for gpa */ - hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT); - if (is_error_pfn(hpaddr)) { + hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); + if (kvm_is_error_hva(hpaddr)) { printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr); return -EINVAL; } hpaddr <<= PAGE_SHIFT; - hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK); +#if PAGE_SHIFT == 12 +#elif PAGE_SHIFT == 16 + hpaddr |= orig_pte->raddr & 0xf000; +#else +#error Unknown page size +#endif /* and write the mapping ea -> hpa into the pt */ vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); @@ -145,7 +161,10 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) } else { struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu); - trace_kvm_book3s_64_mmu_map(rflags, hpteg, va, hpaddr, orig_pte); + dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n", + ((rflags & HPTE_R_PP) == 3) ? '-' : 'w', + (rflags & HPTE_R_N) ? '-' : 'x', + orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr); /* The ppc_md code may give us a secondary entry even though we asked for a primary. Fix up. */ @@ -172,7 +191,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) u16 sid_map_mask; static int backwards_map = 0; - if (vcpu->arch.shared->msr & MSR_PR) + if (vcpu->arch.msr & MSR_PR) gvsid |= VSID_PR; /* We might get collisions that trap in preceding order, so let's @@ -200,7 +219,8 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) map->guest_vsid = gvsid; map->valid = true; - trace_kvm_book3s_slb_map(sid_map_mask, gvsid, map->host_vsid); + dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n", + sid_map_mask, gvsid, map->host_vsid); return map; } @@ -272,7 +292,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) to_svcpu(vcpu)->slb[slb_index].esid = slb_esid; to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid; - trace_kvm_book3s_slbmte(slb_vsid, slb_esid); + dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid); return 0; } @@ -286,7 +306,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) { kvmppc_mmu_hpte_destroy(vcpu); - __destroy_context(to_book3s(vcpu)->context_id[0]); + __destroy_context(to_book3s(vcpu)->context_id); } int kvmppc_mmu_init(struct kvm_vcpu *vcpu) @@ -297,10 +317,10 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu) err = __init_new_context(); if (err < 0) return -1; - vcpu3s->context_id[0] = err; + vcpu3s->context_id = err; - vcpu3s->vsid_max = ((vcpu3s->context_id[0] + 1) << USER_ESID_BITS) - 1; - vcpu3s->vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS; + vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1; + vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS; vcpu3s->vsid_next = vcpu3s->vsid_first; kvmppc_mmu_hpte_init(vcpu); diff --git a/trunk/arch/powerpc/kvm/book3s_emulate.c b/trunk/arch/powerpc/kvm/book3s_emulate.c index 466846557089..c85f906038ce 100644 --- a/trunk/arch/powerpc/kvm/book3s_emulate.c +++ b/trunk/arch/powerpc/kvm/book3s_emulate.c @@ -73,8 +73,8 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, switch (get_xop(inst)) { case OP_19_XOP_RFID: case OP_19_XOP_RFI: - kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0); - kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1); + kvmppc_set_pc(vcpu, vcpu->arch.srr0); + kvmppc_set_msr(vcpu, vcpu->arch.srr1); *advance = 0; break; @@ -86,15 +86,14 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, case 31: switch (get_xop(inst)) { case OP_31_XOP_MFMSR: - kvmppc_set_gpr(vcpu, get_rt(inst), - vcpu->arch.shared->msr); + kvmppc_set_gpr(vcpu, get_rt(inst), vcpu->arch.msr); break; case OP_31_XOP_MTMSRD: { ulong rs = kvmppc_get_gpr(vcpu, get_rs(inst)); if (inst & 0x10000) { - vcpu->arch.shared->msr &= ~(MSR_RI | MSR_EE); - vcpu->arch.shared->msr |= rs & (MSR_RI | MSR_EE); + vcpu->arch.msr &= ~(MSR_RI | MSR_EE); + vcpu->arch.msr |= rs & (MSR_RI | MSR_EE); } else kvmppc_set_msr(vcpu, rs); break; @@ -205,14 +204,14 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, ra = kvmppc_get_gpr(vcpu, get_ra(inst)); addr = (ra + rb) & ~31ULL; - if (!(vcpu->arch.shared->msr & MSR_SF)) + if (!(vcpu->arch.msr & MSR_SF)) addr &= 0xffffffff; vaddr = addr; r = kvmppc_st(vcpu, &addr, 32, zeros, true); if ((r == -ENOENT) || (r == -EPERM)) { *advance = 0; - vcpu->arch.shared->dar = vaddr; + vcpu->arch.dear = vaddr; to_svcpu(vcpu)->fault_dar = vaddr; dsisr = DSISR_ISSTORE; @@ -221,7 +220,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, else if (r == -EPERM) dsisr |= DSISR_PROTFAULT; - vcpu->arch.shared->dsisr = dsisr; + to_book3s(vcpu)->dsisr = dsisr; to_svcpu(vcpu)->fault_dsisr = dsisr; kvmppc_book3s_queue_irqprio(vcpu, @@ -264,7 +263,7 @@ void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, } } -static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn) +static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn) { struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_bat *bat; @@ -286,7 +285,35 @@ static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn) BUG(); } - return bat; + if (sprn % 2) + return bat->raw >> 32; + else + return bat->raw; +} + +static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val) +{ + struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); + struct kvmppc_bat *bat; + + switch (sprn) { + case SPRN_IBAT0U ... SPRN_IBAT3L: + bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; + break; + case SPRN_IBAT4U ... SPRN_IBAT7L: + bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)]; + break; + case SPRN_DBAT0U ... SPRN_DBAT3L: + bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; + break; + case SPRN_DBAT4U ... SPRN_DBAT7L: + bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)]; + break; + default: + BUG(); + } + + kvmppc_set_bat(vcpu, bat, !(sprn % 2), val); } int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) @@ -299,10 +326,10 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) to_book3s(vcpu)->sdr1 = spr_val; break; case SPRN_DSISR: - vcpu->arch.shared->dsisr = spr_val; + to_book3s(vcpu)->dsisr = spr_val; break; case SPRN_DAR: - vcpu->arch.shared->dar = spr_val; + vcpu->arch.dear = spr_val; break; case SPRN_HIOR: to_book3s(vcpu)->hior = spr_val; @@ -311,16 +338,12 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) case SPRN_IBAT4U ... SPRN_IBAT7L: case SPRN_DBAT0U ... SPRN_DBAT3L: case SPRN_DBAT4U ... SPRN_DBAT7L: - { - struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn); - - kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val); + kvmppc_write_bat(vcpu, sprn, (u32)spr_val); /* BAT writes happen so rarely that we're ok to flush * everything here */ kvmppc_mmu_pte_flush(vcpu, 0, 0); kvmppc_mmu_flush_segments(vcpu); break; - } case SPRN_HID0: to_book3s(vcpu)->hid[0] = spr_val; break; @@ -410,24 +433,16 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) case SPRN_IBAT4U ... SPRN_IBAT7L: case SPRN_DBAT0U ... SPRN_DBAT3L: case SPRN_DBAT4U ... SPRN_DBAT7L: - { - struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn); - - if (sprn % 2) - kvmppc_set_gpr(vcpu, rt, bat->raw >> 32); - else - kvmppc_set_gpr(vcpu, rt, bat->raw); - + kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn)); break; - } case SPRN_SDR1: kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1); break; case SPRN_DSISR: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dsisr); + kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->dsisr); break; case SPRN_DAR: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); + kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear); break; case SPRN_HIOR: kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hior); diff --git a/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c b/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c index 79751d8dd131..4868d4a7ebc5 100644 --- a/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c +++ b/trunk/arch/powerpc/kvm/book3s_mmu_hpte.c @@ -21,7 +21,6 @@ #include #include #include -#include "trace.h" #include #include @@ -31,6 +30,14 @@ #define PTE_SIZE 12 +/* #define DEBUG_MMU */ + +#ifdef DEBUG_MMU +#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__) +#else +#define dprintk_mmu(a, ...) do { } while(0) +#endif + static struct kmem_cache *hpte_cache; static inline u64 kvmppc_mmu_hash_pte(u64 eaddr) @@ -38,12 +45,6 @@ static inline u64 kvmppc_mmu_hash_pte(u64 eaddr) return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE); } -static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr) -{ - return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE, - HPTEG_HASH_BITS_PTE_LONG); -} - static inline u64 kvmppc_mmu_hash_vpte(u64 vpage) { return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE); @@ -59,128 +60,77 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { u64 index; - trace_kvm_book3s_mmu_map(pte); - - spin_lock(&vcpu->arch.mmu_lock); - /* Add to ePTE list */ index = kvmppc_mmu_hash_pte(pte->pte.eaddr); - hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]); - - /* Add to ePTE_long list */ - index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr); - hlist_add_head_rcu(&pte->list_pte_long, - &vcpu->arch.hpte_hash_pte_long[index]); + hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]); /* Add to vPTE list */ index = kvmppc_mmu_hash_vpte(pte->pte.vpage); - hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]); + hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]); /* Add to vPTE_long list */ index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage); - hlist_add_head_rcu(&pte->list_vpte_long, - &vcpu->arch.hpte_hash_vpte_long[index]); - - spin_unlock(&vcpu->arch.mmu_lock); -} - -static void free_pte_rcu(struct rcu_head *head) -{ - struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head); - kmem_cache_free(hpte_cache, pte); + hlist_add_head(&pte->list_vpte_long, + &vcpu->arch.hpte_hash_vpte_long[index]); } static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { - trace_kvm_book3s_mmu_invalidate(pte); + dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n", + pte->pte.eaddr, pte->pte.vpage, pte->host_va); /* Different for 32 and 64 bit */ kvmppc_mmu_invalidate_pte(vcpu, pte); - spin_lock(&vcpu->arch.mmu_lock); - - /* pte already invalidated in between? */ - if (hlist_unhashed(&pte->list_pte)) { - spin_unlock(&vcpu->arch.mmu_lock); - return; - } - - hlist_del_init_rcu(&pte->list_pte); - hlist_del_init_rcu(&pte->list_pte_long); - hlist_del_init_rcu(&pte->list_vpte); - hlist_del_init_rcu(&pte->list_vpte_long); - if (pte->pte.may_write) kvm_release_pfn_dirty(pte->pfn); else kvm_release_pfn_clean(pte->pfn); - spin_unlock(&vcpu->arch.mmu_lock); + hlist_del(&pte->list_pte); + hlist_del(&pte->list_vpte); + hlist_del(&pte->list_vpte_long); vcpu->arch.hpte_cache_count--; - call_rcu(&pte->rcu_head, free_pte_rcu); + kmem_cache_free(hpte_cache, pte); } static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) { struct hpte_cache *pte; - struct hlist_node *node; + struct hlist_node *node, *tmp; int i; - rcu_read_lock(); - for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; - hlist_for_each_entry_rcu(pte, node, list, list_vpte_long) + hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) invalidate_pte(vcpu, pte); } - - rcu_read_unlock(); } static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea) { struct hlist_head *list; - struct hlist_node *node; + struct hlist_node *node, *tmp; struct hpte_cache *pte; /* Find the list of entries in the map */ list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)]; - rcu_read_lock(); - /* Check the list for matching entries and invalidate */ - hlist_for_each_entry_rcu(pte, node, list, list_pte) + hlist_for_each_entry_safe(pte, node, tmp, list, list_pte) if ((pte->pte.eaddr & ~0xfffUL) == guest_ea) invalidate_pte(vcpu, pte); - - rcu_read_unlock(); } -static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea) +void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) { - struct hlist_head *list; - struct hlist_node *node; - struct hpte_cache *pte; + u64 i; - /* Find the list of entries in the map */ - list = &vcpu->arch.hpte_hash_pte_long[ - kvmppc_mmu_hash_pte_long(guest_ea)]; + dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n", + vcpu->arch.hpte_cache_count, guest_ea, ea_mask); - rcu_read_lock(); - - /* Check the list for matching entries and invalidate */ - hlist_for_each_entry_rcu(pte, node, list, list_pte_long) - if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea) - invalidate_pte(vcpu, pte); - - rcu_read_unlock(); -} - -void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) -{ - trace_kvm_book3s_mmu_flush("", vcpu, guest_ea, ea_mask); guest_ea &= ea_mask; switch (ea_mask) { @@ -188,7 +138,9 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) kvmppc_mmu_pte_flush_page(vcpu, guest_ea); break; case 0x0ffff000: - kvmppc_mmu_pte_flush_long(vcpu, guest_ea); + /* 32-bit flush w/o segment, go through all possible segments */ + for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL) + kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL); break; case 0: /* Doing a complete flush -> start from scratch */ @@ -204,46 +156,39 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp) { struct hlist_head *list; - struct hlist_node *node; + struct hlist_node *node, *tmp; struct hpte_cache *pte; u64 vp_mask = 0xfffffffffULL; list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)]; - rcu_read_lock(); - /* Check the list for matching entries and invalidate */ - hlist_for_each_entry_rcu(pte, node, list, list_vpte) + hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte) if ((pte->pte.vpage & vp_mask) == guest_vp) invalidate_pte(vcpu, pte); - - rcu_read_unlock(); } /* Flush with mask 0xffffff000 */ static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp) { struct hlist_head *list; - struct hlist_node *node; + struct hlist_node *node, *tmp; struct hpte_cache *pte; u64 vp_mask = 0xffffff000ULL; list = &vcpu->arch.hpte_hash_vpte_long[ kvmppc_mmu_hash_vpte_long(guest_vp)]; - rcu_read_lock(); - /* Check the list for matching entries and invalidate */ - hlist_for_each_entry_rcu(pte, node, list, list_vpte_long) + hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) if ((pte->pte.vpage & vp_mask) == guest_vp) invalidate_pte(vcpu, pte); - - rcu_read_unlock(); } void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) { - trace_kvm_book3s_mmu_flush("v", vcpu, guest_vp, vp_mask); + dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n", + vcpu->arch.hpte_cache_count, guest_vp, vp_mask); guest_vp &= vp_mask; switch(vp_mask) { @@ -261,24 +206,21 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) { - struct hlist_node *node; + struct hlist_node *node, *tmp; struct hpte_cache *pte; int i; - trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end); - - rcu_read_lock(); + dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n", + vcpu->arch.hpte_cache_count, pa_start, pa_end); for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; - hlist_for_each_entry_rcu(pte, node, list, list_vpte_long) + hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) if ((pte->pte.raddr >= pa_start) && (pte->pte.raddr < pa_end)) invalidate_pte(vcpu, pte); } - - rcu_read_unlock(); } struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) @@ -312,15 +254,11 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu) /* init hpte lookup hashes */ kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte, ARRAY_SIZE(vcpu->arch.hpte_hash_pte)); - kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long, - ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long)); kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte, ARRAY_SIZE(vcpu->arch.hpte_hash_vpte)); kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long, ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long)); - spin_lock_init(&vcpu->arch.mmu_lock); - return 0; } diff --git a/trunk/arch/powerpc/kvm/book3s_paired_singles.c b/trunk/arch/powerpc/kvm/book3s_paired_singles.c index 7b0ee96c1bed..35a701f3ece4 100644 --- a/trunk/arch/powerpc/kvm/book3s_paired_singles.c +++ b/trunk/arch/powerpc/kvm/book3s_paired_singles.c @@ -165,15 +165,14 @@ static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt) static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store) { u64 dsisr; - struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared; - shared->msr = kvmppc_set_field(shared->msr, 33, 36, 0); - shared->msr = kvmppc_set_field(shared->msr, 42, 47, 0); - shared->dar = eaddr; + vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 36, 0); + vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0); + vcpu->arch.dear = eaddr; /* Page Fault */ dsisr = kvmppc_set_field(0, 33, 33, 1); if (is_store) - shared->dsisr = kvmppc_set_field(dsisr, 38, 38, 1); + to_book3s(vcpu)->dsisr = kvmppc_set_field(dsisr, 38, 38, 1); kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE); } @@ -659,7 +658,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu) if (!kvmppc_inst_is_paired_single(vcpu, inst)) return EMULATE_FAIL; - if (!(vcpu->arch.shared->msr & MSR_FP)) { + if (!(vcpu->arch.msr & MSR_FP)) { kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL); return EMULATE_AGAIN; } diff --git a/trunk/arch/powerpc/kvm/book3s_rmhandlers.S b/trunk/arch/powerpc/kvm/book3s_rmhandlers.S index 2b9c9088d00e..506d5c316c96 100644 --- a/trunk/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/trunk/arch/powerpc/kvm/book3s_rmhandlers.S @@ -202,25 +202,8 @@ _GLOBAL(kvmppc_rmcall) #if defined(CONFIG_PPC_BOOK3S_32) #define STACK_LR INT_FRAME_SIZE+4 - -/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */ -#define MSR_EXT_START \ - PPC_STL r20, _NIP(r1); \ - mfmsr r20; \ - LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ - andc r3,r20,r3; /* Disable DR,EE */ \ - mtmsr r3; \ - sync - -#define MSR_EXT_END \ - mtmsr r20; /* Enable DR,EE */ \ - sync; \ - PPC_LL r20, _NIP(r1) - #elif defined(CONFIG_PPC_BOOK3S_64) #define STACK_LR _LINK -#define MSR_EXT_START -#define MSR_EXT_END #endif /* @@ -232,12 +215,19 @@ _GLOBAL(kvmppc_load_up_ ## what); \ PPC_STLU r1, -INT_FRAME_SIZE(r1); \ mflr r3; \ PPC_STL r3, STACK_LR(r1); \ - MSR_EXT_START; \ + PPC_STL r20, _NIP(r1); \ + mfmsr r20; \ + LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \ + andc r3,r20,r3; /* Disable DR,EE */ \ + mtmsr r3; \ + sync; \ \ bl FUNC(load_up_ ## what); \ \ - MSR_EXT_END; \ + mtmsr r20; /* Enable DR,EE */ \ + sync; \ PPC_LL r3, STACK_LR(r1); \ + PPC_LL r20, _NIP(r1); \ mtlr r3; \ addi r1, r1, INT_FRAME_SIZE; \ blr @@ -252,10 +242,10 @@ define_load_up(vsx) .global kvmppc_trampoline_lowmem kvmppc_trampoline_lowmem: - PPC_LONG kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START + .long kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START .global kvmppc_trampoline_enter kvmppc_trampoline_enter: - PPC_LONG kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START + .long kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START #include "book3s_segment.S" diff --git a/trunk/arch/powerpc/kvm/booke.c b/trunk/arch/powerpc/kvm/booke.c index 77575d08c818..8d4e35f5372c 100644 --- a/trunk/arch/powerpc/kvm/booke.c +++ b/trunk/arch/powerpc/kvm/booke.c @@ -62,10 +62,9 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) { int i; - printk("pc: %08lx msr: %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr); + printk("pc: %08lx msr: %08lx\n", vcpu->arch.pc, vcpu->arch.msr); printk("lr: %08lx ctr: %08lx\n", vcpu->arch.lr, vcpu->arch.ctr); - printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0, - vcpu->arch.shared->srr1); + printk("srr0: %08lx srr1: %08lx\n", vcpu->arch.srr0, vcpu->arch.srr1); printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions); @@ -131,19 +130,13 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - unsigned int prio = BOOKE_IRQPRIO_EXTERNAL; - - if (irq->irq == KVM_INTERRUPT_SET_LEVEL) - prio = BOOKE_IRQPRIO_EXTERNAL_LEVEL; - - kvmppc_booke_queue_irqprio(vcpu, prio); + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL); } void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); - clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); } /* Deliver the interrupt of the corresponding priority, if possible. */ @@ -153,26 +146,6 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, int allowed = 0; ulong uninitialized_var(msr_mask); bool update_esr = false, update_dear = false; - ulong crit_raw = vcpu->arch.shared->critical; - ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); - bool crit; - bool keep_irq = false; - - /* Truncate crit indicators in 32 bit mode */ - if (!(vcpu->arch.shared->msr & MSR_SF)) { - crit_raw &= 0xffffffff; - crit_r1 &= 0xffffffff; - } - - /* Critical section when crit == r1 */ - crit = (crit_raw == crit_r1); - /* ... and we're in supervisor mode */ - crit = crit && !(vcpu->arch.shared->msr & MSR_PR); - - if (priority == BOOKE_IRQPRIO_EXTERNAL_LEVEL) { - priority = BOOKE_IRQPRIO_EXTERNAL; - keep_irq = true; - } switch (priority) { case BOOKE_IRQPRIO_DTLB_MISS: @@ -196,38 +169,36 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, break; case BOOKE_IRQPRIO_CRITICAL: case BOOKE_IRQPRIO_WATCHDOG: - allowed = vcpu->arch.shared->msr & MSR_CE; + allowed = vcpu->arch.msr & MSR_CE; msr_mask = MSR_ME; break; case BOOKE_IRQPRIO_MACHINE_CHECK: - allowed = vcpu->arch.shared->msr & MSR_ME; + allowed = vcpu->arch.msr & MSR_ME; msr_mask = 0; break; case BOOKE_IRQPRIO_EXTERNAL: case BOOKE_IRQPRIO_DECREMENTER: case BOOKE_IRQPRIO_FIT: - allowed = vcpu->arch.shared->msr & MSR_EE; - allowed = allowed && !crit; + allowed = vcpu->arch.msr & MSR_EE; msr_mask = MSR_CE|MSR_ME|MSR_DE; break; case BOOKE_IRQPRIO_DEBUG: - allowed = vcpu->arch.shared->msr & MSR_DE; + allowed = vcpu->arch.msr & MSR_DE; msr_mask = MSR_ME; break; } if (allowed) { - vcpu->arch.shared->srr0 = vcpu->arch.pc; - vcpu->arch.shared->srr1 = vcpu->arch.shared->msr; + vcpu->arch.srr0 = vcpu->arch.pc; + vcpu->arch.srr1 = vcpu->arch.msr; vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority]; if (update_esr == true) vcpu->arch.esr = vcpu->arch.queued_esr; if (update_dear == true) - vcpu->arch.shared->dar = vcpu->arch.queued_dear; - kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask); + vcpu->arch.dear = vcpu->arch.queued_dear; + kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask); - if (!keep_irq) - clear_bit(priority, &vcpu->arch.pending_exceptions); + clear_bit(priority, &vcpu->arch.pending_exceptions); } return allowed; @@ -237,7 +208,6 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) { unsigned long *pending = &vcpu->arch.pending_exceptions; - unsigned long old_pending = vcpu->arch.pending_exceptions; unsigned int priority; priority = __ffs(*pending); @@ -249,12 +219,6 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) BITS_PER_BYTE * sizeof(*pending), priority + 1); } - - /* Tell the guest about our interrupt status */ - if (*pending) - vcpu->arch.shared->int_pending = 1; - else if (old_pending) - vcpu->arch.shared->int_pending = 0; } /** @@ -301,7 +265,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, break; case BOOKE_INTERRUPT_PROGRAM: - if (vcpu->arch.shared->msr & MSR_PR) { + if (vcpu->arch.msr & MSR_PR) { /* Program traps generated by user-level software must be handled * by the guest kernel. */ kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr); @@ -373,15 +337,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, break; case BOOKE_INTERRUPT_SYSCALL: - if (!(vcpu->arch.shared->msr & MSR_PR) && - (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { - /* KVM PV hypercalls */ - kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); - r = RESUME_GUEST; - } else { - /* Guest syscalls */ - kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL); - } + kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL); kvmppc_account_exit(vcpu, SYSCALL_EXITS); r = RESUME_GUEST; break; @@ -510,19 +466,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { - int i; - vcpu->arch.pc = 0; - vcpu->arch.shared->msr = 0; + vcpu->arch.msr = 0; kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */ vcpu->arch.shadow_pid = 1; - /* Eye-catching numbers so we know if the guest takes an interrupt - * before it's programmed its own IVPR/IVORs. */ + /* Eye-catching number so we know if the guest takes an interrupt + * before it's programmed its own IVPR. */ vcpu->arch.ivpr = 0x55550000; - for (i = 0; i < BOOKE_IRQPRIO_MAX; i++) - vcpu->arch.ivor[i] = 0x7700 | i * 4; kvmppc_init_timing_stats(vcpu); @@ -538,14 +490,14 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) regs->ctr = vcpu->arch.ctr; regs->lr = vcpu->arch.lr; regs->xer = kvmppc_get_xer(vcpu); - regs->msr = vcpu->arch.shared->msr; - regs->srr0 = vcpu->arch.shared->srr0; - regs->srr1 = vcpu->arch.shared->srr1; + regs->msr = vcpu->arch.msr; + regs->srr0 = vcpu->arch.srr0; + regs->srr1 = vcpu->arch.srr1; regs->pid = vcpu->arch.pid; - regs->sprg0 = vcpu->arch.shared->sprg0; - regs->sprg1 = vcpu->arch.shared->sprg1; - regs->sprg2 = vcpu->arch.shared->sprg2; - regs->sprg3 = vcpu->arch.shared->sprg3; + regs->sprg0 = vcpu->arch.sprg0; + regs->sprg1 = vcpu->arch.sprg1; + regs->sprg2 = vcpu->arch.sprg2; + regs->sprg3 = vcpu->arch.sprg3; regs->sprg5 = vcpu->arch.sprg4; regs->sprg6 = vcpu->arch.sprg5; regs->sprg7 = vcpu->arch.sprg6; @@ -566,12 +518,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) vcpu->arch.lr = regs->lr; kvmppc_set_xer(vcpu, regs->xer); kvmppc_set_msr(vcpu, regs->msr); - vcpu->arch.shared->srr0 = regs->srr0; - vcpu->arch.shared->srr1 = regs->srr1; - vcpu->arch.shared->sprg0 = regs->sprg0; - vcpu->arch.shared->sprg1 = regs->sprg1; - vcpu->arch.shared->sprg2 = regs->sprg2; - vcpu->arch.shared->sprg3 = regs->sprg3; + vcpu->arch.srr0 = regs->srr0; + vcpu->arch.srr1 = regs->srr1; + vcpu->arch.sprg0 = regs->sprg0; + vcpu->arch.sprg1 = regs->sprg1; + vcpu->arch.sprg2 = regs->sprg2; + vcpu->arch.sprg3 = regs->sprg3; vcpu->arch.sprg5 = regs->sprg4; vcpu->arch.sprg6 = regs->sprg5; vcpu->arch.sprg7 = regs->sprg6; diff --git a/trunk/arch/powerpc/kvm/booke.h b/trunk/arch/powerpc/kvm/booke.h index 492bb7030358..d59bcca1f9d8 100644 --- a/trunk/arch/powerpc/kvm/booke.h +++ b/trunk/arch/powerpc/kvm/booke.h @@ -46,9 +46,7 @@ #define BOOKE_IRQPRIO_FIT 17 #define BOOKE_IRQPRIO_DECREMENTER 18 #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19 -/* Internal pseudo-irqprio for level triggered externals */ -#define BOOKE_IRQPRIO_EXTERNAL_LEVEL 20 -#define BOOKE_IRQPRIO_MAX 20 +#define BOOKE_IRQPRIO_MAX 19 extern unsigned long kvmppc_booke_handlers; @@ -56,12 +54,12 @@ extern unsigned long kvmppc_booke_handlers; * changing. */ static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) { - if ((new_msr & MSR_PR) != (vcpu->arch.shared->msr & MSR_PR)) + if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR)) kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR); - vcpu->arch.shared->msr = new_msr; + vcpu->arch.msr = new_msr; - if (vcpu->arch.shared->msr & MSR_WE) { + if (vcpu->arch.msr & MSR_WE) { kvm_vcpu_block(vcpu); kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); }; diff --git a/trunk/arch/powerpc/kvm/booke_emulate.c b/trunk/arch/powerpc/kvm/booke_emulate.c index 1260f5f24c0c..cbc790ee1928 100644 --- a/trunk/arch/powerpc/kvm/booke_emulate.c +++ b/trunk/arch/powerpc/kvm/booke_emulate.c @@ -31,8 +31,8 @@ static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) { - vcpu->arch.pc = vcpu->arch.shared->srr0; - kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1); + vcpu->arch.pc = vcpu->arch.srr0; + kvmppc_set_msr(vcpu, vcpu->arch.srr1); } int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, @@ -62,7 +62,7 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, case OP_31_XOP_MFMSR: rt = get_rt(inst); - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr); + kvmppc_set_gpr(vcpu, rt, vcpu->arch.msr); kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS); break; @@ -74,13 +74,13 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, case OP_31_XOP_WRTEE: rs = get_rs(inst); - vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE) + vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | (kvmppc_get_gpr(vcpu, rs) & MSR_EE); kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); break; case OP_31_XOP_WRTEEI: - vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE) + vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | (inst & MSR_EE); kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); break; @@ -105,7 +105,7 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) switch (sprn) { case SPRN_DEAR: - vcpu->arch.shared->dar = spr_val; break; + vcpu->arch.dear = spr_val; break; case SPRN_ESR: vcpu->arch.esr = spr_val; break; case SPRN_DBCR0: @@ -200,7 +200,7 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) case SPRN_IVPR: kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivpr); break; case SPRN_DEAR: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear); break; case SPRN_ESR: kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break; case SPRN_DBCR0: diff --git a/trunk/arch/powerpc/kvm/booke_interrupts.S b/trunk/arch/powerpc/kvm/booke_interrupts.S index 049846911ce4..380a78cf484d 100644 --- a/trunk/arch/powerpc/kvm/booke_interrupts.S +++ b/trunk/arch/powerpc/kvm/booke_interrupts.S @@ -415,8 +415,7 @@ lightweight_exit: lwz r8, VCPU_GPR(r8)(r4) lwz r3, VCPU_PC(r4) mtsrr0 r3 - lwz r3, VCPU_SHARED(r4) - lwz r3, VCPU_SHARED_MSR(r3) + lwz r3, VCPU_MSR(r4) oris r3, r3, KVMPPC_MSR_MASK@h ori r3, r3, KVMPPC_MSR_MASK@l mtsrr1 r3 diff --git a/trunk/arch/powerpc/kvm/e500.c b/trunk/arch/powerpc/kvm/e500.c index 71750f2dd5d3..e8a00b0c4449 100644 --- a/trunk/arch/powerpc/kvm/e500.c +++ b/trunk/arch/powerpc/kvm/e500.c @@ -117,14 +117,8 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) if (err) goto uninit_vcpu; - vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!vcpu->arch.shared) - goto uninit_tlb; - return vcpu; -uninit_tlb: - kvmppc_e500_tlb_uninit(vcpu_e500); uninit_vcpu: kvm_vcpu_uninit(vcpu); free_vcpu: @@ -137,7 +131,6 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); - free_page((unsigned long)vcpu->arch.shared); kvmppc_e500_tlb_uninit(vcpu_e500); kvm_vcpu_uninit(vcpu); kmem_cache_free(kvm_vcpu_cache, vcpu_e500); diff --git a/trunk/arch/powerpc/kvm/e500_tlb.c b/trunk/arch/powerpc/kvm/e500_tlb.c index d6d6d47a75a9..21011e12caeb 100644 --- a/trunk/arch/powerpc/kvm/e500_tlb.c +++ b/trunk/arch/powerpc/kvm/e500_tlb.c @@ -226,7 +226,8 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); stlbe->mas1 = 0; - trace_kvm_stlb_inval(index_of(tlbsel, esel)); + trace_kvm_stlb_inval(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, + stlbe->mas3, stlbe->mas7); } static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, @@ -297,8 +298,7 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, /* Get reference to new page. */ new_page = gfn_to_page(vcpu_e500->vcpu.kvm, gfn); if (is_error_page(new_page)) { - printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", - (long)gfn); + printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn); kvm_release_page_clean(new_page); return; } @@ -314,10 +314,10 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; stlbe->mas2 = (gvaddr & MAS2_EPN) | e500_shadow_mas2_attrib(gtlbe->mas2, - vcpu_e500->vcpu.arch.shared->msr & MSR_PR); + vcpu_e500->vcpu.arch.msr & MSR_PR); stlbe->mas3 = (hpaddr & MAS3_RPN) | e500_shadow_mas3_attrib(gtlbe->mas3, - vcpu_e500->vcpu.arch.shared->msr & MSR_PR); + vcpu_e500->vcpu.arch.msr & MSR_PR); stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN; trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2, @@ -576,28 +576,28 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS); + unsigned int as = !!(vcpu->arch.msr & MSR_IS); return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as); } int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS); + unsigned int as = !!(vcpu->arch.msr & MSR_DS); return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as); } void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS); + unsigned int as = !!(vcpu->arch.msr & MSR_IS); kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as); } void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu) { - unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS); + unsigned int as = !!(vcpu->arch.msr & MSR_DS); kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.fault_dear, as); } diff --git a/trunk/arch/powerpc/kvm/e500_tlb.h b/trunk/arch/powerpc/kvm/e500_tlb.h index 458946b4775d..d28e3010a5e2 100644 --- a/trunk/arch/powerpc/kvm/e500_tlb.h +++ b/trunk/arch/powerpc/kvm/e500_tlb.h @@ -171,7 +171,7 @@ static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, /* Does it match current guest AS? */ /* XXX what about IS != DS? */ - if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS)) + if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) return 0; gpa = get_tlb_raddr(tlbe); diff --git a/trunk/arch/powerpc/kvm/emulate.c b/trunk/arch/powerpc/kvm/emulate.c index c64fd2909bb2..b83ba581fd8e 100644 --- a/trunk/arch/powerpc/kvm/emulate.c +++ b/trunk/arch/powerpc/kvm/emulate.c @@ -242,11 +242,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) switch (sprn) { case SPRN_SRR0: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr0); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr0); break; case SPRN_SRR1: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr1); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr1); break; case SPRN_PVR: kvmppc_set_gpr(vcpu, rt, vcpu->arch.pvr); break; case SPRN_PIR: @@ -263,17 +261,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) kvmppc_set_gpr(vcpu, rt, get_tb()); break; case SPRN_SPRG0: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg0); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg0); break; case SPRN_SPRG1: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg1); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg1); break; case SPRN_SPRG2: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg2); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg2); break; case SPRN_SPRG3: - kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg3); - break; + kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg3); break; /* Note: SPRG4-7 are user-readable, so we don't get * a trap. */ @@ -326,11 +320,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) rs = get_rs(inst); switch (sprn) { case SPRN_SRR0: - vcpu->arch.shared->srr0 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.srr0 = kvmppc_get_gpr(vcpu, rs); break; case SPRN_SRR1: - vcpu->arch.shared->srr1 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.srr1 = kvmppc_get_gpr(vcpu, rs); break; /* XXX We need to context-switch the timebase for * watchdog and FIT. */ @@ -345,17 +337,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) break; case SPRN_SPRG0: - vcpu->arch.shared->sprg0 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.sprg0 = kvmppc_get_gpr(vcpu, rs); break; case SPRN_SPRG1: - vcpu->arch.shared->sprg1 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.sprg1 = kvmppc_get_gpr(vcpu, rs); break; case SPRN_SPRG2: - vcpu->arch.shared->sprg2 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.sprg2 = kvmppc_get_gpr(vcpu, rs); break; case SPRN_SPRG3: - vcpu->arch.shared->sprg3 = kvmppc_get_gpr(vcpu, rs); - break; + vcpu->arch.sprg3 = kvmppc_get_gpr(vcpu, rs); break; default: emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, rs); diff --git a/trunk/arch/powerpc/kvm/powerpc.c b/trunk/arch/powerpc/kvm/powerpc.c index 2f87a1627f6c..72a4ad86ee91 100644 --- a/trunk/arch/powerpc/kvm/powerpc.c +++ b/trunk/arch/powerpc/kvm/powerpc.c @@ -38,56 +38,9 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) { - return !(v->arch.shared->msr & MSR_WE) || - !!(v->arch.pending_exceptions); + return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions); } -int kvmppc_kvm_pv(struct kvm_vcpu *vcpu) -{ - int nr = kvmppc_get_gpr(vcpu, 11); - int r; - unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3); - unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4); - unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5); - unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6); - unsigned long r2 = 0; - - if (!(vcpu->arch.shared->msr & MSR_SF)) { - /* 32 bit mode */ - param1 &= 0xffffffff; - param2 &= 0xffffffff; - param3 &= 0xffffffff; - param4 &= 0xffffffff; - } - - switch (nr) { - case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE: - { - vcpu->arch.magic_page_pa = param1; - vcpu->arch.magic_page_ea = param2; - - r2 = KVM_MAGIC_FEAT_SR; - - r = HC_EV_SUCCESS; - break; - } - case HC_VENDOR_KVM | KVM_HC_FEATURES: - r = HC_EV_SUCCESS; -#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */ - r2 |= (1 << KVM_FEATURE_MAGIC_PAGE); -#endif - - /* Second return value is in r4 */ - break; - default: - r = HC_EV_UNIMPLEMENTED; - break; - } - - kvmppc_set_gpr(vcpu, 4, r2); - - return r; -} int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) { @@ -192,10 +145,8 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_PPC_SEGSTATE: case KVM_CAP_PPC_PAIRED_SINGLES: case KVM_CAP_PPC_UNSET_IRQ: - case KVM_CAP_PPC_IRQ_LEVEL: case KVM_CAP_ENABLE_CAP: case KVM_CAP_PPC_OSI: - case KVM_CAP_PPC_GET_PVINFO: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -583,53 +534,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp, return r; } -static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo) -{ - u32 inst_lis = 0x3c000000; - u32 inst_ori = 0x60000000; - u32 inst_nop = 0x60000000; - u32 inst_sc = 0x44000002; - u32 inst_imm_mask = 0xffff; - - /* - * The hypercall to get into KVM from within guest context is as - * follows: - * - * lis r0, r0, KVM_SC_MAGIC_R0@h - * ori r0, KVM_SC_MAGIC_R0@l - * sc - * nop - */ - pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask); - pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask); - pvinfo->hcall[2] = inst_sc; - pvinfo->hcall[3] = inst_nop; - - return 0; -} - long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - void __user *argp = (void __user *)arg; long r; switch (ioctl) { - case KVM_PPC_GET_PVINFO: { - struct kvm_ppc_pvinfo pvinfo; - r = kvm_vm_ioctl_get_pvinfo(&pvinfo); - if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) { - r = -EFAULT; - goto out; - } - - break; - } default: r = -ENOTTY; } -out: return r; } diff --git a/trunk/arch/powerpc/kvm/trace.h b/trunk/arch/powerpc/kvm/trace.h index 3aca1b042b8c..a8e840018052 100644 --- a/trunk/arch/powerpc/kvm/trace.h +++ b/trunk/arch/powerpc/kvm/trace.h @@ -98,245 +98,6 @@ TRACE_EVENT(kvm_gtlb_write, __entry->word1, __entry->word2) ); - -/************************************************************************* - * Book3S trace points * - *************************************************************************/ - -#ifdef CONFIG_PPC_BOOK3S - -TRACE_EVENT(kvm_book3s_exit, - TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu), - TP_ARGS(exit_nr, vcpu), - - TP_STRUCT__entry( - __field( unsigned int, exit_nr ) - __field( unsigned long, pc ) - __field( unsigned long, msr ) - __field( unsigned long, dar ) - __field( unsigned long, srr1 ) - ), - - TP_fast_assign( - __entry->exit_nr = exit_nr; - __entry->pc = kvmppc_get_pc(vcpu); - __entry->dar = kvmppc_get_fault_dar(vcpu); - __entry->msr = vcpu->arch.shared->msr; - __entry->srr1 = to_svcpu(vcpu)->shadow_srr1; - ), - - TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx", - __entry->exit_nr, __entry->pc, __entry->msr, __entry->dar, - __entry->srr1) -); - -TRACE_EVENT(kvm_book3s_reenter, - TP_PROTO(int r, struct kvm_vcpu *vcpu), - TP_ARGS(r, vcpu), - - TP_STRUCT__entry( - __field( unsigned int, r ) - __field( unsigned long, pc ) - ), - - TP_fast_assign( - __entry->r = r; - __entry->pc = kvmppc_get_pc(vcpu); - ), - - TP_printk("reentry r=%d | pc=0x%lx", __entry->r, __entry->pc) -); - -#ifdef CONFIG_PPC_BOOK3S_64 - -TRACE_EVENT(kvm_book3s_64_mmu_map, - TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr, - struct kvmppc_pte *orig_pte), - TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte), - - TP_STRUCT__entry( - __field( unsigned char, flag_w ) - __field( unsigned char, flag_x ) - __field( unsigned long, eaddr ) - __field( unsigned long, hpteg ) - __field( unsigned long, va ) - __field( unsigned long long, vpage ) - __field( unsigned long, hpaddr ) - ), - - TP_fast_assign( - __entry->flag_w = ((rflags & HPTE_R_PP) == 3) ? '-' : 'w'; - __entry->flag_x = (rflags & HPTE_R_N) ? '-' : 'x'; - __entry->eaddr = orig_pte->eaddr; - __entry->hpteg = hpteg; - __entry->va = va; - __entry->vpage = orig_pte->vpage; - __entry->hpaddr = hpaddr; - ), - - TP_printk("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx", - __entry->flag_w, __entry->flag_x, __entry->eaddr, - __entry->hpteg, __entry->va, __entry->vpage, __entry->hpaddr) -); - -#endif /* CONFIG_PPC_BOOK3S_64 */ - -TRACE_EVENT(kvm_book3s_mmu_map, - TP_PROTO(struct hpte_cache *pte), - TP_ARGS(pte), - - TP_STRUCT__entry( - __field( u64, host_va ) - __field( u64, pfn ) - __field( ulong, eaddr ) - __field( u64, vpage ) - __field( ulong, raddr ) - __field( int, flags ) - ), - - TP_fast_assign( - __entry->host_va = pte->host_va; - __entry->pfn = pte->pfn; - __entry->eaddr = pte->pte.eaddr; - __entry->vpage = pte->pte.vpage; - __entry->raddr = pte->pte.raddr; - __entry->flags = (pte->pte.may_read ? 0x4 : 0) | - (pte->pte.may_write ? 0x2 : 0) | - (pte->pte.may_execute ? 0x1 : 0); - ), - - TP_printk("Map: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]", - __entry->host_va, __entry->pfn, __entry->eaddr, - __entry->vpage, __entry->raddr, __entry->flags) -); - -TRACE_EVENT(kvm_book3s_mmu_invalidate, - TP_PROTO(struct hpte_cache *pte), - TP_ARGS(pte), - - TP_STRUCT__entry( - __field( u64, host_va ) - __field( u64, pfn ) - __field( ulong, eaddr ) - __field( u64, vpage ) - __field( ulong, raddr ) - __field( int, flags ) - ), - - TP_fast_assign( - __entry->host_va = pte->host_va; - __entry->pfn = pte->pfn; - __entry->eaddr = pte->pte.eaddr; - __entry->vpage = pte->pte.vpage; - __entry->raddr = pte->pte.raddr; - __entry->flags = (pte->pte.may_read ? 0x4 : 0) | - (pte->pte.may_write ? 0x2 : 0) | - (pte->pte.may_execute ? 0x1 : 0); - ), - - TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]", - __entry->host_va, __entry->pfn, __entry->eaddr, - __entry->vpage, __entry->raddr, __entry->flags) -); - -TRACE_EVENT(kvm_book3s_mmu_flush, - TP_PROTO(const char *type, struct kvm_vcpu *vcpu, unsigned long long p1, - unsigned long long p2), - TP_ARGS(type, vcpu, p1, p2), - - TP_STRUCT__entry( - __field( int, count ) - __field( unsigned long long, p1 ) - __field( unsigned long long, p2 ) - __field( const char *, type ) - ), - - TP_fast_assign( - __entry->count = vcpu->arch.hpte_cache_count; - __entry->p1 = p1; - __entry->p2 = p2; - __entry->type = type; - ), - - TP_printk("Flush %d %sPTEs: %llx - %llx", - __entry->count, __entry->type, __entry->p1, __entry->p2) -); - -TRACE_EVENT(kvm_book3s_slb_found, - TP_PROTO(unsigned long long gvsid, unsigned long long hvsid), - TP_ARGS(gvsid, hvsid), - - TP_STRUCT__entry( - __field( unsigned long long, gvsid ) - __field( unsigned long long, hvsid ) - ), - - TP_fast_assign( - __entry->gvsid = gvsid; - __entry->hvsid = hvsid; - ), - - TP_printk("%llx -> %llx", __entry->gvsid, __entry->hvsid) -); - -TRACE_EVENT(kvm_book3s_slb_fail, - TP_PROTO(u16 sid_map_mask, unsigned long long gvsid), - TP_ARGS(sid_map_mask, gvsid), - - TP_STRUCT__entry( - __field( unsigned short, sid_map_mask ) - __field( unsigned long long, gvsid ) - ), - - TP_fast_assign( - __entry->sid_map_mask = sid_map_mask; - __entry->gvsid = gvsid; - ), - - TP_printk("%x/%x: %llx", __entry->sid_map_mask, - SID_MAP_MASK - __entry->sid_map_mask, __entry->gvsid) -); - -TRACE_EVENT(kvm_book3s_slb_map, - TP_PROTO(u16 sid_map_mask, unsigned long long gvsid, - unsigned long long hvsid), - TP_ARGS(sid_map_mask, gvsid, hvsid), - - TP_STRUCT__entry( - __field( unsigned short, sid_map_mask ) - __field( unsigned long long, guest_vsid ) - __field( unsigned long long, host_vsid ) - ), - - TP_fast_assign( - __entry->sid_map_mask = sid_map_mask; - __entry->guest_vsid = gvsid; - __entry->host_vsid = hvsid; - ), - - TP_printk("%x: %llx -> %llx", __entry->sid_map_mask, - __entry->guest_vsid, __entry->host_vsid) -); - -TRACE_EVENT(kvm_book3s_slbmte, - TP_PROTO(u64 slb_vsid, u64 slb_esid), - TP_ARGS(slb_vsid, slb_esid), - - TP_STRUCT__entry( - __field( u64, slb_vsid ) - __field( u64, slb_esid ) - ), - - TP_fast_assign( - __entry->slb_vsid = slb_vsid; - __entry->slb_esid = slb_esid; - ), - - TP_printk("%llx, %llx", __entry->slb_vsid, __entry->slb_esid) -); - -#endif /* CONFIG_PPC_BOOK3S */ - #endif /* _TRACE_KVM_H */ /* This part must be outside protection */ diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig index 956154f32cfe..81c9208025fa 100644 --- a/trunk/arch/powerpc/platforms/Kconfig +++ b/trunk/arch/powerpc/platforms/Kconfig @@ -21,16 +21,6 @@ source "arch/powerpc/platforms/44x/Kconfig" source "arch/powerpc/platforms/40x/Kconfig" source "arch/powerpc/platforms/amigaone/Kconfig" -config KVM_GUEST - bool "KVM Guest support" - default y - ---help--- - This option enables various optimizations for running under the KVM - hypervisor. Overhead for the kernel when not running inside KVM should - be minimal. - - In case of doubt, say Y - config PPC_NATIVE bool depends on 6xx || PPC64 diff --git a/trunk/arch/s390/include/asm/Kbuild b/trunk/arch/s390/include/asm/Kbuild index 287d7bbb6d36..42e512ba8b43 100644 --- a/trunk/arch/s390/include/asm/Kbuild +++ b/trunk/arch/s390/include/asm/Kbuild @@ -5,7 +5,6 @@ header-y += chsc.h header-y += cmb.h header-y += dasd.h header-y += debug.h -header-y += kvm_virtio.h header-y += monwriter.h header-y += qeth.h header-y += schid.h diff --git a/trunk/arch/s390/include/asm/kvm_virtio.h b/trunk/arch/s390/include/asm/kvm_virtio.h index 72f614181eff..acdfdff26611 100644 --- a/trunk/arch/s390/include/asm/kvm_virtio.h +++ b/trunk/arch/s390/include/asm/kvm_virtio.h @@ -54,11 +54,4 @@ struct kvm_vqconfig { * This is pagesize for historical reasons. */ #define KVM_S390_VIRTIO_RING_ALIGN 4096 - -/* These values are supposed to be in ext_params on an interrupt */ -#define VIRTIO_PARAM_MASK 0xff -#define VIRTIO_PARAM_VRING_INTERRUPT 0x0 -#define VIRTIO_PARAM_CONFIG_CHANGED 0x1 -#define VIRTIO_PARAM_DEV_ADD 0x2 - #endif diff --git a/trunk/arch/x86/include/asm/kvm_emulate.h b/trunk/arch/x86/include/asm/kvm_emulate.h index b36c6b3fe144..1f99ecfc48e1 100644 --- a/trunk/arch/x86/include/asm/kvm_emulate.h +++ b/trunk/arch/x86/include/asm/kvm_emulate.h @@ -139,7 +139,6 @@ struct x86_emulate_ops { void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu); unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu); void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu); - void (*get_idt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu); ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu); int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu); int (*cpl)(struct kvm_vcpu *vcpu); @@ -157,10 +156,7 @@ struct operand { unsigned long orig_val; u64 orig_val64; }; - union { - unsigned long *reg; - unsigned long mem; - } addr; + unsigned long *ptr; union { unsigned long val; u64 val64; @@ -194,7 +190,6 @@ struct decode_cache { bool has_seg_override; u8 seg_override; unsigned int d; - int (*execute)(struct x86_emulate_ctxt *ctxt); unsigned long regs[NR_VCPU_REGS]; unsigned long eip; /* modrm */ @@ -202,16 +197,17 @@ struct decode_cache { u8 modrm_mod; u8 modrm_reg; u8 modrm_rm; - u8 modrm_seg; + u8 use_modrm_ea; bool rip_relative; + unsigned long modrm_ea; + void *modrm_ptr; + unsigned long modrm_val; struct fetch_cache fetch; struct read_cache io_read; struct read_cache mem_read; }; struct x86_emulate_ctxt { - struct x86_emulate_ops *ops; - /* Register state before/after emulation. */ struct kvm_vcpu *vcpu; @@ -224,11 +220,12 @@ struct x86_emulate_ctxt { /* interruptibility state, as a result of execution of STI or MOV SS */ int interruptibility; - bool perm_ok; /* do not check permissions if true */ + bool restart; /* restart string instruction after writeback */ int exception; /* exception that happens during emulation or -1 */ u32 error_code; /* error code for exception */ bool error_code_valid; + unsigned long cr2; /* faulted address in case of #PF */ /* decode cache */ struct decode_cache decode; @@ -252,14 +249,13 @@ struct x86_emulate_ctxt { #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 #endif -int x86_decode_insn(struct x86_emulate_ctxt *ctxt); -#define EMULATION_FAILED -1 -#define EMULATION_OK 0 -#define EMULATION_RESTART 1 -int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); +int x86_decode_insn(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops); +int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops); int emulator_task_switch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, u16 tss_selector, int reason, bool has_error_code, u32 error_code); -int emulate_int_real(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, int irq); + #endif /* _ASM_X86_KVM_X86_EMULATE_H */ diff --git a/trunk/arch/x86/include/asm/kvm_host.h b/trunk/arch/x86/include/asm/kvm_host.h index 9e6fe391094e..c52e2eb40a1e 100644 --- a/trunk/arch/x86/include/asm/kvm_host.h +++ b/trunk/arch/x86/include/asm/kvm_host.h @@ -236,14 +236,10 @@ struct kvm_pio_request { */ struct kvm_mmu { void (*new_cr3)(struct kvm_vcpu *vcpu); - void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root); - unsigned long (*get_cr3)(struct kvm_vcpu *vcpu); int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err); - void (*inject_page_fault)(struct kvm_vcpu *vcpu); void (*free)(struct kvm_vcpu *vcpu); gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access, u32 *error); - gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access); void (*prefetch_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page); int (*sync_page)(struct kvm_vcpu *vcpu, @@ -253,18 +249,13 @@ struct kvm_mmu { int root_level; int shadow_root_level; union kvm_mmu_page_role base_role; - bool direct_map; u64 *pae_root; - u64 *lm_root; u64 rsvd_bits_mask[2][4]; - - bool nx; - - u64 pdptrs[4]; /* pae */ }; struct kvm_vcpu_arch { + u64 host_tsc; /* * rip and regs accesses must go through * kvm_{register,rip}_{read,write} functions. @@ -281,6 +272,7 @@ struct kvm_vcpu_arch { unsigned long cr4_guest_owned_bits; unsigned long cr8; u32 hflags; + u64 pdptrs[4]; /* pae */ u64 efer; u64 apic_base; struct kvm_lapic *apic; /* kernel irqchip context */ @@ -290,41 +282,7 @@ struct kvm_vcpu_arch { u64 ia32_misc_enable_msr; bool tpr_access_reporting; - /* - * Paging state of the vcpu - * - * If the vcpu runs in guest mode with two level paging this still saves - * the paging mode of the l1 guest. This context is always used to - * handle faults. - */ struct kvm_mmu mmu; - - /* - * Paging state of an L2 guest (used for nested npt) - * - * This context will save all necessary information to walk page tables - * of the an L2 guest. This context is only initialized for page table - * walking and not for faulting since we never handle l2 page faults on - * the host. - */ - struct kvm_mmu nested_mmu; - - /* - * Pointer to the mmu context currently used for - * gva_to_gpa translations. - */ - struct kvm_mmu *walk_mmu; - - /* - * This struct is filled with the necessary information to propagate a - * page fault into the guest - */ - struct { - u64 address; - unsigned error_code; - bool nested; - } fault; - /* only needed in kvm_pv_mmu_op() path, but it's hot so * put it here to avoid allocation */ struct kvm_pv_mmu_op_buffer mmu_op_buffer; @@ -378,15 +336,9 @@ struct kvm_vcpu_arch { gpa_t time; struct pvclock_vcpu_time_info hv_clock; - unsigned int hw_tsc_khz; + unsigned int hv_clock_tsc_khz; unsigned int time_offset; struct page *time_page; - u64 last_host_tsc; - u64 last_guest_tsc; - u64 last_kernel_ns; - u64 last_tsc_nsec; - u64 last_tsc_write; - bool tsc_catchup; bool nmi_pending; bool nmi_injected; @@ -415,9 +367,9 @@ struct kvm_vcpu_arch { }; struct kvm_arch { - unsigned int n_used_mmu_pages; + unsigned int n_free_mmu_pages; unsigned int n_requested_mmu_pages; - unsigned int n_max_mmu_pages; + unsigned int n_alloc_mmu_pages; atomic_t invlpg_counter; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; /* @@ -442,14 +394,8 @@ struct kvm_arch { gpa_t ept_identity_map_addr; unsigned long irq_sources_bitmap; + u64 vm_init_tsc; s64 kvmclock_offset; - spinlock_t tsc_write_lock; - u64 last_tsc_nsec; - u64 last_tsc_offset; - u64 last_tsc_write; - u32 virtual_tsc_khz; - u32 virtual_tsc_mult; - s8 virtual_tsc_shift; struct kvm_xen_hvm_config xen_hvm_config; @@ -559,7 +505,6 @@ struct kvm_x86_ops { void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr, bool has_error_code, u32 error_code, bool reinject); - void (*cancel_injection)(struct kvm_vcpu *vcpu); int (*interrupt_allowed)(struct kvm_vcpu *vcpu); int (*nmi_allowed)(struct kvm_vcpu *vcpu); bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); @@ -572,16 +517,11 @@ struct kvm_x86_ops { u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); int (*get_lpage_level)(void); bool (*rdtscp_supported)(void); - void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment); - - void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry); bool (*has_wbinvd_exit)(void); - void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset); - const struct trace_print_flags *exit_reasons_str; }; @@ -604,7 +544,7 @@ void kvm_mmu_zap_all(struct kvm *kvm); unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); -int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3); +int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, const void *val, int bytes); @@ -668,11 +608,8 @@ void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr); void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr); void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); -void kvm_inject_page_fault(struct kvm_vcpu *vcpu); -int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gfn_t gfn, void *data, int offset, int len, - u32 access); -void kvm_propagate_fault(struct kvm_vcpu *vcpu); +void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2, + u32 error_code); bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl); int kvm_pic_set_irq(void *opaque, int irq, int level); diff --git a/trunk/arch/x86/include/asm/kvm_para.h b/trunk/arch/x86/include/asm/kvm_para.h index 7b562b6184bc..05eba5e9a8e8 100644 --- a/trunk/arch/x86/include/asm/kvm_para.h +++ b/trunk/arch/x86/include/asm/kvm_para.h @@ -158,12 +158,6 @@ static inline unsigned int kvm_arch_para_features(void) return cpuid_eax(KVM_CPUID_FEATURES); } -#ifdef CONFIG_KVM_GUEST -void __init kvm_guest_init(void); -#else -#define kvm_guest_init() do { } while (0) #endif -#endif /* __KERNEL__ */ - #endif /* _ASM_X86_KVM_PARA_H */ diff --git a/trunk/arch/x86/include/asm/msr-index.h b/trunk/arch/x86/include/asm/msr-index.h index 83c4bb1d917d..986f7790fdb2 100644 --- a/trunk/arch/x86/include/asm/msr-index.h +++ b/trunk/arch/x86/include/asm/msr-index.h @@ -198,7 +198,6 @@ #define MSR_IA32_TSC 0x00000010 #define MSR_IA32_PLATFORM_ID 0x00000017 #define MSR_IA32_EBL_CR_POWERON 0x0000002a -#define MSR_EBC_FREQUENCY_ID 0x0000002c #define MSR_IA32_FEATURE_CONTROL 0x0000003a #define FEATURE_CONTROL_LOCKED (1<<0) diff --git a/trunk/arch/x86/include/asm/pvclock.h b/trunk/arch/x86/include/asm/pvclock.h index 7f7e577a0e39..cd02f324aa6b 100644 --- a/trunk/arch/x86/include/asm/pvclock.h +++ b/trunk/arch/x86/include/asm/pvclock.h @@ -12,42 +12,4 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall, struct pvclock_vcpu_time_info *vcpu, struct timespec *ts); -/* - * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, - * yielding a 64-bit result. - */ -static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) -{ - u64 product; -#ifdef __i386__ - u32 tmp1, tmp2; -#endif - - if (shift < 0) - delta >>= -shift; - else - delta <<= shift; - -#ifdef __i386__ - __asm__ ( - "mul %5 ; " - "mov %4,%%eax ; " - "mov %%edx,%4 ; " - "mul %5 ; " - "xor %5,%5 ; " - "add %4,%%eax ; " - "adc %5,%%edx ; " - : "=A" (product), "=r" (tmp1), "=r" (tmp2) - : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); -#elif defined(__x86_64__) - __asm__ ( - "mul %%rdx ; shrd $32,%%rdx,%%rax" - : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) ); -#else -#error implement me! -#endif - - return product; -} - #endif /* _ASM_X86_PVCLOCK_H */ diff --git a/trunk/arch/x86/kernel/apm_32.c b/trunk/arch/x86/kernel/apm_32.c index 0e4f24c2a746..fbbc4dadecc4 100644 --- a/trunk/arch/x86/kernel/apm_32.c +++ b/trunk/arch/x86/kernel/apm_32.c @@ -189,8 +189,8 @@ * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01. * * [This document is available free from Intel by calling 800.628.8686 (fax - * 916.356.6100) or 800.548.4725; or from - * http://www.microsoft.com/whdc/archive/amp_12.mspx It is also + * 916.356.6100) or 800.548.4725; or via anonymous ftp from + * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also * available from Microsoft by calling 206.882.8080.] * * APM 1.2 Reference: diff --git a/trunk/arch/x86/kernel/kvmclock.c b/trunk/arch/x86/kernel/kvmclock.c index ca43ce31a19c..eb9b76c716c2 100644 --- a/trunk/arch/x86/kernel/kvmclock.c +++ b/trunk/arch/x86/kernel/kvmclock.c @@ -128,15 +128,13 @@ static struct clocksource kvm_clock = { static int kvm_register_clock(char *txt) { int cpu = smp_processor_id(); - int low, high, ret; - + int low, high; low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1; high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32); - ret = native_write_msr_safe(msr_kvm_system_time, low, high); printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n", cpu, high, low, txt); - return ret; + return native_write_msr_safe(msr_kvm_system_time, low, high); } #ifdef CONFIG_X86_LOCAL_APIC diff --git a/trunk/arch/x86/kernel/microcode_core.c b/trunk/arch/x86/kernel/microcode_core.c index 1cca374a2bac..0b3d37e83606 100644 --- a/trunk/arch/x86/kernel/microcode_core.c +++ b/trunk/arch/x86/kernel/microcode_core.c @@ -12,7 +12,7 @@ * Software Developer's Manual * Order Number 253668 or free download from: * - * http://developer.intel.com/Assets/PDF/manual/253668.pdf + * http://developer.intel.com/design/pentium4/manuals/253668.htm * * For more information, go to http://www.urbanmyth.org/microcode * diff --git a/trunk/arch/x86/kernel/microcode_intel.c b/trunk/arch/x86/kernel/microcode_intel.c index dcb65cc0a053..356170262a93 100644 --- a/trunk/arch/x86/kernel/microcode_intel.c +++ b/trunk/arch/x86/kernel/microcode_intel.c @@ -12,7 +12,7 @@ * Software Developer's Manual * Order Number 253668 or free download from: * - * http://developer.intel.com/Assets/PDF/manual/253668.pdf + * http://developer.intel.com/design/pentium4/manuals/253668.htm * * For more information, go to http://www.urbanmyth.org/microcode * diff --git a/trunk/arch/x86/kernel/pvclock.c b/trunk/arch/x86/kernel/pvclock.c index bab3b9e6f66d..239427ca02af 100644 --- a/trunk/arch/x86/kernel/pvclock.c +++ b/trunk/arch/x86/kernel/pvclock.c @@ -82,8 +82,7 @@ static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift) static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow) { u64 delta = native_read_tsc() - shadow->tsc_timestamp; - return pvclock_scale_delta(delta, shadow->tsc_to_nsec_mul, - shadow->tsc_shift); + return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); } /* diff --git a/trunk/arch/x86/kvm/Kconfig b/trunk/arch/x86/kvm/Kconfig index ddc131ff438f..970bbd479516 100644 --- a/trunk/arch/x86/kvm/Kconfig +++ b/trunk/arch/x86/kvm/Kconfig @@ -64,13 +64,6 @@ config KVM_AMD To compile this as a module, choose M here: the module will be called kvm-amd. -config KVM_MMU_AUDIT - bool "Audit KVM MMU" - depends on KVM && TRACEPOINTS - ---help--- - This option adds a R/W kVM module parameter 'mmu_audit', which allows - audit KVM MMU at runtime. - # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. source drivers/vhost/Kconfig diff --git a/trunk/arch/x86/kvm/emulate.c b/trunk/arch/x86/kvm/emulate.c index 38b6e8dafaff..66ca98aafdd6 100644 --- a/trunk/arch/x86/kvm/emulate.c +++ b/trunk/arch/x86/kvm/emulate.c @@ -9,7 +9,7 @@ * privileged instructions: * * Copyright (C) 2006 Qumranet - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Avi Kivity * Yaniv Kamay @@ -51,13 +51,13 @@ #define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ #define DstReg (2<<1) /* Register operand. */ #define DstMem (3<<1) /* Memory operand. */ -#define DstAcc (4<<1) /* Destination Accumulator */ +#define DstAcc (4<<1) /* Destination Accumulator */ #define DstDI (5<<1) /* Destination is in ES:(E)DI */ #define DstMem64 (6<<1) /* 64bit memory operand */ -#define DstImmUByte (7<<1) /* 8-bit unsigned immediate operand */ #define DstMask (7<<1) /* Source operand type. */ #define SrcNone (0<<4) /* No source operand. */ +#define SrcImplicit (0<<4) /* Source operand is implicit in the opcode. */ #define SrcReg (1<<4) /* Register operand. */ #define SrcMem (2<<4) /* Memory operand. */ #define SrcMem16 (3<<4) /* Memory operand (16-bit). */ @@ -71,7 +71,6 @@ #define SrcImmFAddr (0xb<<4) /* Source is immediate far address */ #define SrcMemFAddr (0xc<<4) /* Source is far address in memory */ #define SrcAcc (0xd<<4) /* Source Accumulator */ -#define SrcImmU16 (0xe<<4) /* Immediate operand, unsigned, 16 bits */ #define SrcMask (0xf<<4) /* Generic ModRM decode. */ #define ModRM (1<<8) @@ -83,10 +82,8 @@ #define Stack (1<<13) /* Stack instruction (push/pop) */ #define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */ #define GroupDual (1<<15) /* Alternate decoding of mod == 3 */ +#define GroupMask 0xff /* Group number stored in bits 0:7 */ /* Misc flags */ -#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */ -#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */ -#define Undefined (1<<25) /* No Such Instruction */ #define Lock (1<<26) /* lock prefix is allowed for the instruction */ #define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */ #define No64 (1<<28) @@ -95,30 +92,285 @@ #define Src2CL (1<<29) #define Src2ImmByte (2<<29) #define Src2One (3<<29) -#define Src2Imm (4<<29) #define Src2Mask (7<<29) -#define X2(x...) x, x -#define X3(x...) X2(x), x -#define X4(x...) X2(x), X2(x) -#define X5(x...) X4(x), x -#define X6(x...) X4(x), X2(x) -#define X7(x...) X4(x), X3(x) -#define X8(x...) X4(x), X4(x) -#define X16(x...) X8(x), X8(x) - -struct opcode { - u32 flags; - union { - int (*execute)(struct x86_emulate_ctxt *ctxt); - struct opcode *group; - struct group_dual *gdual; - } u; +enum { + Group1_80, Group1_81, Group1_82, Group1_83, + Group1A, Group3_Byte, Group3, Group4, Group5, Group7, + Group8, Group9, }; -struct group_dual { - struct opcode mod012[8]; - struct opcode mod3[8]; +static u32 opcode_table[256] = { + /* 0x00 - 0x07 */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, + ImplicitOps | Stack | No64, ImplicitOps | Stack | No64, + /* 0x08 - 0x0F */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, + ImplicitOps | Stack | No64, 0, + /* 0x10 - 0x17 */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, + ImplicitOps | Stack | No64, ImplicitOps | Stack | No64, + /* 0x18 - 0x1F */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, + ImplicitOps | Stack | No64, ImplicitOps | Stack | No64, + /* 0x20 - 0x27 */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0, + /* 0x28 - 0x2F */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0, + /* 0x30 - 0x37 */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0, + /* 0x38 - 0x3F */ + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, + ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, + 0, 0, + /* 0x40 - 0x47 */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x48 - 0x4F */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x50 - 0x57 */ + SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, + SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, + /* 0x58 - 0x5F */ + DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack, + DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack, + /* 0x60 - 0x67 */ + ImplicitOps | Stack | No64, ImplicitOps | Stack | No64, + 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , + 0, 0, 0, 0, + /* 0x68 - 0x6F */ + SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0, + DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */ + SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */ + /* 0x70 - 0x77 */ + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + /* 0x78 - 0x7F */ + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + /* 0x80 - 0x87 */ + Group | Group1_80, Group | Group1_81, + Group | Group1_82, Group | Group1_83, + ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + /* 0x88 - 0x8F */ + ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, + ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstMem | SrcNone | ModRM | Mov, ModRM | DstReg, + ImplicitOps | SrcMem16 | ModRM, Group | Group1A, + /* 0x90 - 0x97 */ + DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, + /* 0x98 - 0x9F */ + 0, 0, SrcImmFAddr | No64, 0, + ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, + /* 0xA0 - 0xA7 */ + ByteOp | DstAcc | SrcMem | Mov | MemAbs, DstAcc | SrcMem | Mov | MemAbs, + ByteOp | DstMem | SrcAcc | Mov | MemAbs, DstMem | SrcAcc | Mov | MemAbs, + ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String, + ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String, + /* 0xA8 - 0xAF */ + DstAcc | SrcImmByte | ByteOp, DstAcc | SrcImm, ByteOp | DstDI | Mov | String, DstDI | Mov | String, + ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String, + ByteOp | DstDI | String, DstDI | String, + /* 0xB0 - 0xB7 */ + ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, + ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, + ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, + ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov, + /* 0xB8 - 0xBF */ + DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, + DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, + DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, + DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, + /* 0xC0 - 0xC7 */ + ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, + 0, ImplicitOps | Stack, 0, 0, + ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov, + /* 0xC8 - 0xCF */ + 0, 0, 0, ImplicitOps | Stack, + ImplicitOps, SrcImmByte, ImplicitOps | No64, ImplicitOps, + /* 0xD0 - 0xD7 */ + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, + 0, 0, 0, 0, + /* 0xD8 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xE7 */ + 0, 0, 0, 0, + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc, + ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc, + /* 0xE8 - 0xEF */ + SrcImm | Stack, SrcImm | ImplicitOps, + SrcImmFAddr | No64, SrcImmByte | ImplicitOps, + SrcNone | ByteOp | DstAcc, SrcNone | DstAcc, + SrcNone | ByteOp | DstAcc, SrcNone | DstAcc, + /* 0xF0 - 0xF7 */ + 0, 0, 0, 0, + ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3, + /* 0xF8 - 0xFF */ + ImplicitOps, 0, ImplicitOps, ImplicitOps, + ImplicitOps, ImplicitOps, Group | Group4, Group | Group5, +}; + +static u32 twobyte_table[256] = { + /* 0x00 - 0x0F */ + 0, Group | GroupDual | Group7, 0, 0, + 0, ImplicitOps, ImplicitOps | Priv, 0, + ImplicitOps | Priv, ImplicitOps | Priv, 0, 0, + 0, ImplicitOps | ModRM, 0, 0, + /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 - 0x2F */ + ModRM | ImplicitOps | Priv, ModRM | Priv, + ModRM | ImplicitOps | Priv, ModRM | Priv, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 - 0x3F */ + ImplicitOps | Priv, 0, ImplicitOps | Priv, 0, + ImplicitOps, ImplicitOps | Priv, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x48 - 0x4F */ + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x8F */ + SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, + SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + ImplicitOps | Stack, ImplicitOps | Stack, + 0, DstMem | SrcReg | ModRM | BitOp, + DstMem | SrcReg | Src2ImmByte | ModRM, + DstMem | SrcReg | Src2CL | ModRM, 0, 0, + /* 0xA8 - 0xAF */ + ImplicitOps | Stack, ImplicitOps | Stack, + 0, DstMem | SrcReg | ModRM | BitOp | Lock, + DstMem | SrcReg | Src2ImmByte | ModRM, + DstMem | SrcReg | Src2CL | ModRM, + ModRM, 0, + /* 0xB0 - 0xB7 */ + ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock, + 0, DstMem | SrcReg | ModRM | BitOp | Lock, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xB8 - 0xBF */ + 0, 0, + Group | Group8, DstMem | SrcReg | ModRM | BitOp | Lock, + 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, + DstReg | SrcMem16 | ModRM | Mov, + /* 0xC0 - 0xCF */ + 0, 0, 0, DstMem | SrcReg | ModRM | Mov, + 0, 0, 0, Group | GroupDual | Group9, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static u32 group_table[] = { + [Group1_80*8] = + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM | Lock, + ByteOp | DstMem | SrcImm | ModRM, + [Group1_81*8] = + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM | Lock, + DstMem | SrcImm | ModRM, + [Group1_82*8] = + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64 | Lock, + ByteOp | DstMem | SrcImm | ModRM | No64, + [Group1_83*8] = + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM, + [Group1A*8] = + DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0, + [Group3_Byte*8] = + ByteOp | SrcImm | DstMem | ModRM, ByteOp | SrcImm | DstMem | ModRM, + ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, + 0, 0, 0, 0, + [Group3*8] = + DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, + DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, + 0, 0, 0, 0, + [Group4*8] = + ByteOp | DstMem | SrcNone | ModRM | Lock, ByteOp | DstMem | SrcNone | ModRM | Lock, + 0, 0, 0, 0, 0, 0, + [Group5*8] = + DstMem | SrcNone | ModRM | Lock, DstMem | SrcNone | ModRM | Lock, + SrcMem | ModRM | Stack, 0, + SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps, + SrcMem | ModRM | Stack, 0, + [Group7*8] = + 0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv, + SrcNone | ModRM | DstMem | Mov, 0, + SrcMem16 | ModRM | Mov | Priv, SrcMem | ModRM | ByteOp | Priv, + [Group8*8] = + 0, 0, 0, 0, + DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock, + DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock, + [Group9*8] = + 0, DstMem64 | ModRM | Lock, 0, 0, 0, 0, 0, 0, +}; + +static u32 group2_table[] = { + [Group7*8] = + SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM | Priv, + SrcNone | ModRM | DstMem | Mov, 0, + SrcMem16 | ModRM | Mov | Priv, 0, + [Group9*8] = + 0, 0, 0, 0, 0, 0, 0, 0, }; /* EFLAGS bit definitions. */ @@ -140,9 +392,6 @@ struct group_dual { #define EFLG_PF (1<<2) #define EFLG_CF (1<<0) -#define EFLG_RESERVED_ZEROS_MASK 0xffc0802a -#define EFLG_RESERVED_ONE_MASK 2 - /* * Instruction emulation: * Most instructions are emulated directly via a fragment of inline assembly @@ -195,13 +444,13 @@ struct group_dual { #define ON64(x) #endif -#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix, _dsttype) \ +#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix) \ do { \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0", "4", "2") \ _op _suffix " %"_x"3,%1; " \ _POST_EFLAGS("0", "4", "2") \ - : "=m" (_eflags), "+q" (*(_dsttype*)&(_dst).val),\ + : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : _y ((_src).val), "i" (EFLAGS_MASK)); \ } while (0) @@ -214,13 +463,13 @@ struct group_dual { \ switch ((_dst).bytes) { \ case 2: \ - ____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w",u16);\ + ____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w"); \ break; \ case 4: \ - ____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l",u32);\ + ____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l"); \ break; \ case 8: \ - ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q",u64)); \ + ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q")); \ break; \ } \ } while (0) @@ -230,7 +479,7 @@ struct group_dual { unsigned long _tmp; \ switch ((_dst).bytes) { \ case 1: \ - ____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b",u8); \ + ____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b"); \ break; \ default: \ __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ @@ -317,74 +566,6 @@ struct group_dual { } \ } while (0) -#define __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, _suffix) \ - do { \ - unsigned long _tmp; \ - \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0", "4", "1") \ - _op _suffix " %5; " \ - _POST_EFLAGS("0", "4", "1") \ - : "=m" (_eflags), "=&r" (_tmp), \ - "+a" (_rax), "+d" (_rdx) \ - : "i" (EFLAGS_MASK), "m" ((_src).val), \ - "a" (_rax), "d" (_rdx)); \ - } while (0) - -#define __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _suffix, _ex) \ - do { \ - unsigned long _tmp; \ - \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0", "5", "1") \ - "1: \n\t" \ - _op _suffix " %6; " \ - "2: \n\t" \ - _POST_EFLAGS("0", "5", "1") \ - ".pushsection .fixup,\"ax\" \n\t" \ - "3: movb $1, %4 \n\t" \ - "jmp 2b \n\t" \ - ".popsection \n\t" \ - _ASM_EXTABLE(1b, 3b) \ - : "=m" (_eflags), "=&r" (_tmp), \ - "+a" (_rax), "+d" (_rdx), "+qm"(_ex) \ - : "i" (EFLAGS_MASK), "m" ((_src).val), \ - "a" (_rax), "d" (_rdx)); \ - } while (0) - -/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */ -#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags) \ - do { \ - switch((_src).bytes) { \ - case 1: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "b"); break; \ - case 2: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "w"); break; \ - case 4: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "l"); break; \ - case 8: ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "q")); break; \ - } \ - } while (0) - -#define emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _ex) \ - do { \ - switch((_src).bytes) { \ - case 1: \ - __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \ - _eflags, "b", _ex); \ - break; \ - case 2: \ - __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \ - _eflags, "w", _ex); \ - break; \ - case 4: \ - __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \ - _eflags, "l", _ex); \ - break; \ - case 8: ON64( \ - __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \ - _eflags, "q", _ex)); \ - break; \ - } \ - } while (0) - /* Fetch next part of the instruction being emulated. */ #define insn_fetch(_type, _size, _eip) \ ({ unsigned long _x; \ @@ -480,6 +661,7 @@ static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, ctxt->exception = vec; ctxt->error_code = error; ctxt->error_code_valid = valid; + ctxt->restart = false; } static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err) @@ -487,9 +669,11 @@ static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err) emulate_exception(ctxt, GP_VECTOR, err, true); } -static void emulate_pf(struct x86_emulate_ctxt *ctxt) +static void emulate_pf(struct x86_emulate_ctxt *ctxt, unsigned long addr, + int err) { - emulate_exception(ctxt, PF_VECTOR, 0, true); + ctxt->cr2 = addr; + emulate_exception(ctxt, PF_VECTOR, err, true); } static void emulate_ud(struct x86_emulate_ctxt *ctxt) @@ -502,12 +686,6 @@ static void emulate_ts(struct x86_emulate_ctxt *ctxt, int err) emulate_exception(ctxt, TS_VECTOR, err, true); } -static int emulate_de(struct x86_emulate_ctxt *ctxt) -{ - emulate_exception(ctxt, DE_VECTOR, 0, false); - return X86EMUL_PROPAGATE_FAULT; -} - static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, unsigned long eip, u8 *dest) @@ -564,7 +742,7 @@ static void *decode_register(u8 modrm_reg, unsigned long *regs, static int read_descriptor(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, - ulong addr, + void *ptr, u16 *size, unsigned long *address, int op_bytes) { int rc; @@ -572,10 +750,12 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, if (op_bytes == 2) op_bytes = 3; *address = 0; - rc = ops->read_std(addr, (unsigned long *)size, 2, ctxt->vcpu, NULL); + rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, + ctxt->vcpu, NULL); if (rc != X86EMUL_CONTINUE) return rc; - rc = ops->read_std(addr + 2, address, op_bytes, ctxt->vcpu, NULL); + rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, + ctxt->vcpu, NULL); return rc; } @@ -614,24 +794,6 @@ static int test_cc(unsigned int condition, unsigned int flags) return (!!rc ^ (condition & 1)); } -static void fetch_register_operand(struct operand *op) -{ - switch (op->bytes) { - case 1: - op->val = *(u8 *)op->addr.reg; - break; - case 2: - op->val = *(u16 *)op->addr.reg; - break; - case 4: - op->val = *(u32 *)op->addr.reg; - break; - case 8: - op->val = *(u64 *)op->addr.reg; - break; - } -} - static void decode_register_operand(struct operand *op, struct decode_cache *c, int inhibit_bytereg) @@ -643,25 +805,34 @@ static void decode_register_operand(struct operand *op, reg = (c->b & 7) | ((c->rex_prefix & 1) << 3); op->type = OP_REG; if ((c->d & ByteOp) && !inhibit_bytereg) { - op->addr.reg = decode_register(reg, c->regs, highbyte_regs); + op->ptr = decode_register(reg, c->regs, highbyte_regs); + op->val = *(u8 *)op->ptr; op->bytes = 1; } else { - op->addr.reg = decode_register(reg, c->regs, 0); + op->ptr = decode_register(reg, c->regs, 0); op->bytes = c->op_bytes; + switch (op->bytes) { + case 2: + op->val = *(u16 *)op->ptr; + break; + case 4: + op->val = *(u32 *)op->ptr; + break; + case 8: + op->val = *(u64 *) op->ptr; + break; + } } - fetch_register_operand(op); op->orig_val = op->val; } static int decode_modrm(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - struct operand *op) + struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; u8 sib; int index_reg = 0, base_reg = 0, scale; int rc = X86EMUL_CONTINUE; - ulong modrm_ea = 0; if (c->rex_prefix) { c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ @@ -673,19 +844,16 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, c->modrm_mod |= (c->modrm & 0xc0) >> 6; c->modrm_reg |= (c->modrm & 0x38) >> 3; c->modrm_rm |= (c->modrm & 0x07); - c->modrm_seg = VCPU_SREG_DS; + c->modrm_ea = 0; + c->use_modrm_ea = 1; if (c->modrm_mod == 3) { - op->type = OP_REG; - op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - op->addr.reg = decode_register(c->modrm_rm, + c->modrm_ptr = decode_register(c->modrm_rm, c->regs, c->d & ByteOp); - fetch_register_operand(op); + c->modrm_val = *(unsigned long *)c->modrm_ptr; return rc; } - op->type = OP_MEM; - if (c->ad_bytes == 2) { unsigned bx = c->regs[VCPU_REGS_RBX]; unsigned bp = c->regs[VCPU_REGS_RBP]; @@ -696,46 +864,47 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, switch (c->modrm_mod) { case 0: if (c->modrm_rm == 6) - modrm_ea += insn_fetch(u16, 2, c->eip); + c->modrm_ea += insn_fetch(u16, 2, c->eip); break; case 1: - modrm_ea += insn_fetch(s8, 1, c->eip); + c->modrm_ea += insn_fetch(s8, 1, c->eip); break; case 2: - modrm_ea += insn_fetch(u16, 2, c->eip); + c->modrm_ea += insn_fetch(u16, 2, c->eip); break; } switch (c->modrm_rm) { case 0: - modrm_ea += bx + si; + c->modrm_ea += bx + si; break; case 1: - modrm_ea += bx + di; + c->modrm_ea += bx + di; break; case 2: - modrm_ea += bp + si; + c->modrm_ea += bp + si; break; case 3: - modrm_ea += bp + di; + c->modrm_ea += bp + di; break; case 4: - modrm_ea += si; + c->modrm_ea += si; break; case 5: - modrm_ea += di; + c->modrm_ea += di; break; case 6: if (c->modrm_mod != 0) - modrm_ea += bp; + c->modrm_ea += bp; break; case 7: - modrm_ea += bx; + c->modrm_ea += bx; break; } if (c->modrm_rm == 2 || c->modrm_rm == 3 || (c->modrm_rm == 6 && c->modrm_mod != 0)) - c->modrm_seg = VCPU_SREG_SS; - modrm_ea = (u16)modrm_ea; + if (!c->has_seg_override) + set_seg_override(c, VCPU_SREG_SS); + c->modrm_ea = (u16)c->modrm_ea; } else { /* 32/64-bit ModR/M decode. */ if ((c->modrm_rm & 7) == 4) { @@ -745,153 +914,489 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, scale = sib >> 6; if ((base_reg & 7) == 5 && c->modrm_mod == 0) - modrm_ea += insn_fetch(s32, 4, c->eip); + c->modrm_ea += insn_fetch(s32, 4, c->eip); else - modrm_ea += c->regs[base_reg]; + c->modrm_ea += c->regs[base_reg]; if (index_reg != 4) - modrm_ea += c->regs[index_reg] << scale; + c->modrm_ea += c->regs[index_reg] << scale; } else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) { if (ctxt->mode == X86EMUL_MODE_PROT64) c->rip_relative = 1; } else - modrm_ea += c->regs[c->modrm_rm]; + c->modrm_ea += c->regs[c->modrm_rm]; switch (c->modrm_mod) { case 0: if (c->modrm_rm == 5) - modrm_ea += insn_fetch(s32, 4, c->eip); + c->modrm_ea += insn_fetch(s32, 4, c->eip); break; case 1: - modrm_ea += insn_fetch(s8, 1, c->eip); + c->modrm_ea += insn_fetch(s8, 1, c->eip); break; case 2: - modrm_ea += insn_fetch(s32, 4, c->eip); + c->modrm_ea += insn_fetch(s32, 4, c->eip); break; } } - op->addr.mem = modrm_ea; done: return rc; } static int decode_abs(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - struct operand *op) + struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; - op->type = OP_MEM; switch (c->ad_bytes) { case 2: - op->addr.mem = insn_fetch(u16, 2, c->eip); + c->modrm_ea = insn_fetch(u16, 2, c->eip); break; case 4: - op->addr.mem = insn_fetch(u32, 4, c->eip); + c->modrm_ea = insn_fetch(u32, 4, c->eip); break; case 8: - op->addr.mem = insn_fetch(u64, 8, c->eip); + c->modrm_ea = insn_fetch(u64, 8, c->eip); break; } done: return rc; } -static void fetch_bit_operand(struct decode_cache *c) +int +x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - long sv = 0, mask; + struct decode_cache *c = &ctxt->decode; + int rc = X86EMUL_CONTINUE; + int mode = ctxt->mode; + int def_op_bytes, def_ad_bytes, group; - if (c->dst.type == OP_MEM && c->src.type == OP_REG) { - mask = ~(c->dst.bytes * 8 - 1); - if (c->src.bytes == 2) - sv = (s16)c->src.val & (s16)mask; - else if (c->src.bytes == 4) - sv = (s32)c->src.val & (s32)mask; + /* we cannot decode insn before we complete previous rep insn */ + WARN_ON(ctxt->restart); - c->dst.addr.mem += (sv >> 3); - } + c->eip = ctxt->eip; + c->fetch.start = c->fetch.end = c->eip; + ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS); - /* only subword offset */ - c->src.val &= (c->dst.bytes << 3) - 1; -} + switch (mode) { + case X86EMUL_MODE_REAL: + case X86EMUL_MODE_VM86: + case X86EMUL_MODE_PROT16: + def_op_bytes = def_ad_bytes = 2; + break; + case X86EMUL_MODE_PROT32: + def_op_bytes = def_ad_bytes = 4; + break; +#ifdef CONFIG_X86_64 + case X86EMUL_MODE_PROT64: + def_op_bytes = 4; + def_ad_bytes = 8; + break; +#endif + default: + return -1; + } -static int read_emulated(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - unsigned long addr, void *dest, unsigned size) -{ - int rc; - struct read_cache *mc = &ctxt->decode.mem_read; - u32 err; + c->op_bytes = def_op_bytes; + c->ad_bytes = def_ad_bytes; - while (size) { - int n = min(size, 8u); - size -= n; - if (mc->pos < mc->end) - goto read_cached; + /* Legacy prefixes. */ + for (;;) { + switch (c->b = insn_fetch(u8, 1, c->eip)) { + case 0x66: /* operand-size override */ + /* switch between 2/4 bytes */ + c->op_bytes = def_op_bytes ^ 6; + break; + case 0x67: /* address-size override */ + if (mode == X86EMUL_MODE_PROT64) + /* switch between 4/8 bytes */ + c->ad_bytes = def_ad_bytes ^ 12; + else + /* switch between 2/4 bytes */ + c->ad_bytes = def_ad_bytes ^ 6; + break; + case 0x26: /* ES override */ + case 0x2e: /* CS override */ + case 0x36: /* SS override */ + case 0x3e: /* DS override */ + set_seg_override(c, (c->b >> 3) & 3); + break; + case 0x64: /* FS override */ + case 0x65: /* GS override */ + set_seg_override(c, c->b & 7); + break; + case 0x40 ... 0x4f: /* REX */ + if (mode != X86EMUL_MODE_PROT64) + goto done_prefixes; + c->rex_prefix = c->b; + continue; + case 0xf0: /* LOCK */ + c->lock_prefix = 1; + break; + case 0xf2: /* REPNE/REPNZ */ + c->rep_prefix = REPNE_PREFIX; + break; + case 0xf3: /* REP/REPE/REPZ */ + c->rep_prefix = REPE_PREFIX; + break; + default: + goto done_prefixes; + } - rc = ops->read_emulated(addr, mc->data + mc->end, n, &err, - ctxt->vcpu); - if (rc == X86EMUL_PROPAGATE_FAULT) - emulate_pf(ctxt); - if (rc != X86EMUL_CONTINUE) - return rc; - mc->end += n; + /* Any legacy prefix after a REX prefix nullifies its effect. */ - read_cached: - memcpy(dest, mc->data + mc->pos, n); - mc->pos += n; - dest += n; - addr += n; + c->rex_prefix = 0; } - return X86EMUL_CONTINUE; -} -static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - unsigned int size, unsigned short port, - void *dest) -{ - struct read_cache *rc = &ctxt->decode.io_read; +done_prefixes: - if (rc->pos == rc->end) { /* refill pio read ahead */ - struct decode_cache *c = &ctxt->decode; - unsigned int in_page, n; - unsigned int count = c->rep_prefix ? - address_mask(c, c->regs[VCPU_REGS_RCX]) : 1; - in_page = (ctxt->eflags & EFLG_DF) ? - offset_in_page(c->regs[VCPU_REGS_RDI]) : - PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]); - n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size, - count); - if (n == 0) - n = 1; - rc->pos = rc->end = 0; - if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu)) - return 0; - rc->end = n * size; + /* REX prefix. */ + if (c->rex_prefix) + if (c->rex_prefix & 8) + c->op_bytes = 8; /* REX.W */ + + /* Opcode byte(s). */ + c->d = opcode_table[c->b]; + if (c->d == 0) { + /* Two-byte opcode? */ + if (c->b == 0x0f) { + c->twobyte = 1; + c->b = insn_fetch(u8, 1, c->eip); + c->d = twobyte_table[c->b]; + } } - memcpy(dest, rc->data + rc->pos, size); - rc->pos += size; - return 1; -} + if (c->d & Group) { + group = c->d & GroupMask; + c->modrm = insn_fetch(u8, 1, c->eip); + --c->eip; -static u32 desc_limit_scaled(struct desc_struct *desc) -{ - u32 limit = get_desc_limit(desc); + group = (group << 3) + ((c->modrm >> 3) & 7); + if ((c->d & GroupDual) && (c->modrm >> 6) == 3) + c->d = group2_table[group]; + else + c->d = group_table[group]; + } - return desc->g ? (limit << 12) | 0xfff : limit; -} + /* Unrecognised? */ + if (c->d == 0) { + DPRINTF("Cannot emulate %02x\n", c->b); + return -1; + } -static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - u16 selector, struct desc_ptr *dt) -{ - if (selector & 1 << 2) { - struct desc_struct desc; - memset (dt, 0, sizeof *dt); - if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu)) - return; + if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) + c->op_bytes = 8; + + /* ModRM and SIB bytes. */ + if (c->d & ModRM) + rc = decode_modrm(ctxt, ops); + else if (c->d & MemAbs) + rc = decode_abs(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; + + if (!c->has_seg_override) + set_seg_override(c, VCPU_SREG_DS); + + if (!(!c->twobyte && c->b == 0x8d)) + c->modrm_ea += seg_override_base(ctxt, ops, c); + + if (c->ad_bytes != 8) + c->modrm_ea = (u32)c->modrm_ea; + + if (c->rip_relative) + c->modrm_ea += c->eip; + + /* + * Decode and fetch the source operand: register, memory + * or immediate. + */ + switch (c->d & SrcMask) { + case SrcNone: + break; + case SrcReg: + decode_register_operand(&c->src, c, 0); + break; + case SrcMem16: + c->src.bytes = 2; + goto srcmem_common; + case SrcMem32: + c->src.bytes = 4; + goto srcmem_common; + case SrcMem: + c->src.bytes = (c->d & ByteOp) ? 1 : + c->op_bytes; + /* Don't fetch the address for invlpg: it could be unmapped. */ + if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7) + break; + srcmem_common: + /* + * For instructions with a ModR/M byte, switch to register + * access if Mod = 3. + */ + if ((c->d & ModRM) && c->modrm_mod == 3) { + c->src.type = OP_REG; + c->src.val = c->modrm_val; + c->src.ptr = c->modrm_ptr; + break; + } + c->src.type = OP_MEM; + c->src.ptr = (unsigned long *)c->modrm_ea; + c->src.val = 0; + break; + case SrcImm: + case SrcImmU: + c->src.type = OP_IMM; + c->src.ptr = (unsigned long *)c->eip; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + if (c->src.bytes == 8) + c->src.bytes = 4; + /* NB. Immediates are sign-extended as necessary. */ + switch (c->src.bytes) { + case 1: + c->src.val = insn_fetch(s8, 1, c->eip); + break; + case 2: + c->src.val = insn_fetch(s16, 2, c->eip); + break; + case 4: + c->src.val = insn_fetch(s32, 4, c->eip); + break; + } + if ((c->d & SrcMask) == SrcImmU) { + switch (c->src.bytes) { + case 1: + c->src.val &= 0xff; + break; + case 2: + c->src.val &= 0xffff; + break; + case 4: + c->src.val &= 0xffffffff; + break; + } + } + break; + case SrcImmByte: + case SrcImmUByte: + c->src.type = OP_IMM; + c->src.ptr = (unsigned long *)c->eip; + c->src.bytes = 1; + if ((c->d & SrcMask) == SrcImmByte) + c->src.val = insn_fetch(s8, 1, c->eip); + else + c->src.val = insn_fetch(u8, 1, c->eip); + break; + case SrcAcc: + c->src.type = OP_REG; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->src.ptr = &c->regs[VCPU_REGS_RAX]; + switch (c->src.bytes) { + case 1: + c->src.val = *(u8 *)c->src.ptr; + break; + case 2: + c->src.val = *(u16 *)c->src.ptr; + break; + case 4: + c->src.val = *(u32 *)c->src.ptr; + break; + case 8: + c->src.val = *(u64 *)c->src.ptr; + break; + } + break; + case SrcOne: + c->src.bytes = 1; + c->src.val = 1; + break; + case SrcSI: + c->src.type = OP_MEM; + c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->src.ptr = (unsigned long *) + register_address(c, seg_override_base(ctxt, ops, c), + c->regs[VCPU_REGS_RSI]); + c->src.val = 0; + break; + case SrcImmFAddr: + c->src.type = OP_IMM; + c->src.ptr = (unsigned long *)c->eip; + c->src.bytes = c->op_bytes + 2; + insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip); + break; + case SrcMemFAddr: + c->src.type = OP_MEM; + c->src.ptr = (unsigned long *)c->modrm_ea; + c->src.bytes = c->op_bytes + 2; + break; + } + + /* + * Decode and fetch the second source operand: register, memory + * or immediate. + */ + switch (c->d & Src2Mask) { + case Src2None: + break; + case Src2CL: + c->src2.bytes = 1; + c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8; + break; + case Src2ImmByte: + c->src2.type = OP_IMM; + c->src2.ptr = (unsigned long *)c->eip; + c->src2.bytes = 1; + c->src2.val = insn_fetch(u8, 1, c->eip); + break; + case Src2One: + c->src2.bytes = 1; + c->src2.val = 1; + break; + } + + /* Decode and fetch the destination operand: register or memory. */ + switch (c->d & DstMask) { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + return 0; + case DstReg: + decode_register_operand(&c->dst, c, + c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); + break; + case DstMem: + case DstMem64: + if ((c->d & ModRM) && c->modrm_mod == 3) { + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.type = OP_REG; + c->dst.val = c->dst.orig_val = c->modrm_val; + c->dst.ptr = c->modrm_ptr; + break; + } + c->dst.type = OP_MEM; + c->dst.ptr = (unsigned long *)c->modrm_ea; + if ((c->d & DstMask) == DstMem64) + c->dst.bytes = 8; + else + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.val = 0; + if (c->d & BitOp) { + unsigned long mask = ~(c->dst.bytes * 8 - 1); + + c->dst.ptr = (void *)c->dst.ptr + + (c->src.val & mask) / 8; + } + break; + case DstAcc: + c->dst.type = OP_REG; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = &c->regs[VCPU_REGS_RAX]; + switch (c->dst.bytes) { + case 1: + c->dst.val = *(u8 *)c->dst.ptr; + break; + case 2: + c->dst.val = *(u16 *)c->dst.ptr; + break; + case 4: + c->dst.val = *(u32 *)c->dst.ptr; + break; + case 8: + c->dst.val = *(u64 *)c->dst.ptr; + break; + } + c->dst.orig_val = c->dst.val; + break; + case DstDI: + c->dst.type = OP_MEM; + c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; + c->dst.ptr = (unsigned long *) + register_address(c, es_base(ctxt, ops), + c->regs[VCPU_REGS_RDI]); + c->dst.val = 0; + break; + } + +done: + return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; +} + +static int read_emulated(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long addr, void *dest, unsigned size) +{ + int rc; + struct read_cache *mc = &ctxt->decode.mem_read; + u32 err; + + while (size) { + int n = min(size, 8u); + size -= n; + if (mc->pos < mc->end) + goto read_cached; + + rc = ops->read_emulated(addr, mc->data + mc->end, n, &err, + ctxt->vcpu); + if (rc == X86EMUL_PROPAGATE_FAULT) + emulate_pf(ctxt, addr, err); + if (rc != X86EMUL_CONTINUE) + return rc; + mc->end += n; + + read_cached: + memcpy(dest, mc->data + mc->pos, n); + mc->pos += n; + dest += n; + addr += n; + } + return X86EMUL_CONTINUE; +} + +static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned int size, unsigned short port, + void *dest) +{ + struct read_cache *rc = &ctxt->decode.io_read; + + if (rc->pos == rc->end) { /* refill pio read ahead */ + struct decode_cache *c = &ctxt->decode; + unsigned int in_page, n; + unsigned int count = c->rep_prefix ? + address_mask(c, c->regs[VCPU_REGS_RCX]) : 1; + in_page = (ctxt->eflags & EFLG_DF) ? + offset_in_page(c->regs[VCPU_REGS_RDI]) : + PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]); + n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size, + count); + if (n == 0) + n = 1; + rc->pos = rc->end = 0; + if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu)) + return 0; + rc->end = n * size; + } + + memcpy(dest, rc->data + rc->pos, size); + rc->pos += size; + return 1; +} + +static u32 desc_limit_scaled(struct desc_struct *desc) +{ + u32 limit = get_desc_limit(desc); + + return desc->g ? (limit << 12) | 0xfff : limit; +} + +static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + u16 selector, struct desc_ptr *dt) +{ + if (selector & 1 << 2) { + struct desc_struct desc; + memset (dt, 0, sizeof *dt); + if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu)) + return; dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */ dt->address = get_desc_base(&desc); @@ -919,7 +1424,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, addr = dt.address + index * 8; ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, &err); if (ret == X86EMUL_PROPAGATE_FAULT) - emulate_pf(ctxt); + emulate_pf(ctxt, addr, err); return ret; } @@ -945,7 +1450,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, addr = dt.address + index * 8; ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err); if (ret == X86EMUL_PROPAGATE_FAULT) - emulate_pf(ctxt); + emulate_pf(ctxt, addr, err); return ret; } @@ -1068,25 +1573,6 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, return X86EMUL_PROPAGATE_FAULT; } -static void write_register_operand(struct operand *op) -{ - /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ - switch (op->bytes) { - case 1: - *(u8 *)op->addr.reg = (u8)op->val; - break; - case 2: - *(u16 *)op->addr.reg = (u16)op->val; - break; - case 4: - *op->addr.reg = (u32)op->val; - break; /* 64b: zero-extend */ - case 8: - *op->addr.reg = op->val; - break; - } -} - static inline int writeback(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { @@ -1096,12 +1582,28 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, switch (c->dst.type) { case OP_REG: - write_register_operand(&c->dst); + /* The 4-byte case *is* correct: + * in 64-bit mode we zero-extend. + */ + switch (c->dst.bytes) { + case 1: + *(u8 *)c->dst.ptr = (u8)c->dst.val; + break; + case 2: + *(u16 *)c->dst.ptr = (u16)c->dst.val; + break; + case 4: + *c->dst.ptr = (u32)c->dst.val; + break; /* 64b: zero-ext */ + case 8: + *c->dst.ptr = c->dst.val; + break; + } break; case OP_MEM: if (c->lock_prefix) rc = ops->cmpxchg_emulated( - c->dst.addr.mem, + (unsigned long)c->dst.ptr, &c->dst.orig_val, &c->dst.val, c->dst.bytes, @@ -1109,13 +1611,14 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, ctxt->vcpu); else rc = ops->write_emulated( - c->dst.addr.mem, + (unsigned long)c->dst.ptr, &c->dst.val, c->dst.bytes, &err, ctxt->vcpu); if (rc == X86EMUL_PROPAGATE_FAULT) - emulate_pf(ctxt); + emulate_pf(ctxt, + (unsigned long)c->dst.ptr, err); if (rc != X86EMUL_CONTINUE) return rc; break; @@ -1137,8 +1640,8 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt, c->dst.bytes = c->op_bytes; c->dst.val = c->src.val; register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); - c->dst.addr.mem = register_address(c, ss_base(ctxt, ops), - c->regs[VCPU_REGS_RSP]); + c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops), + c->regs[VCPU_REGS_RSP]); } static int emulate_pop(struct x86_emulate_ctxt *ctxt, @@ -1198,9 +1701,6 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt, *(unsigned long *)dest = (ctxt->eflags & ~change_mask) | (val & change_mask); - if (rc == X86EMUL_PROPAGATE_FAULT) - emulate_pf(ctxt); - return rc; } @@ -1278,157 +1778,13 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt, return rc; } -int emulate_int_real(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, int irq) +static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; - int rc; - struct desc_ptr dt; - gva_t cs_addr; - gva_t eip_addr; - u16 cs, eip; - u32 err; - - /* TODO: Add limit checks */ - c->src.val = ctxt->eflags; - emulate_push(ctxt, ops); - rc = writeback(ctxt, ops); - if (rc != X86EMUL_CONTINUE) - return rc; - ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC); - - c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu); - emulate_push(ctxt, ops); - rc = writeback(ctxt, ops); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->src.val = c->eip; - emulate_push(ctxt, ops); - rc = writeback(ctxt, ops); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->dst.type = OP_NONE; - - ops->get_idt(&dt, ctxt->vcpu); - - eip_addr = dt.address + (irq << 2); - cs_addr = dt.address + (irq << 2) + 2; - - rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &err); - if (rc != X86EMUL_CONTINUE) - return rc; - - rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &err); - if (rc != X86EMUL_CONTINUE) - return rc; - - rc = load_segment_descriptor(ctxt, ops, cs, VCPU_SREG_CS); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->eip = eip; - - return rc; -} - -static int emulate_int(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, int irq) -{ - switch(ctxt->mode) { - case X86EMUL_MODE_REAL: - return emulate_int_real(ctxt, ops, irq); - case X86EMUL_MODE_VM86: - case X86EMUL_MODE_PROT16: - case X86EMUL_MODE_PROT32: - case X86EMUL_MODE_PROT64: - default: - /* Protected mode interrupts unimplemented yet */ - return X86EMUL_UNHANDLEABLE; - } -} - -static int emulate_iret_real(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops) -{ - struct decode_cache *c = &ctxt->decode; - int rc = X86EMUL_CONTINUE; - unsigned long temp_eip = 0; - unsigned long temp_eflags = 0; - unsigned long cs = 0; - unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF | - EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF | - EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */ - unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP; - - /* TODO: Add stack limit check */ - - rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes); - - if (rc != X86EMUL_CONTINUE) - return rc; - - if (temp_eip & ~0xffff) { - emulate_gp(ctxt, 0); - return X86EMUL_PROPAGATE_FAULT; - } - - rc = emulate_pop(ctxt, ops, &cs, c->op_bytes); - - if (rc != X86EMUL_CONTINUE) - return rc; - - rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes); - - if (rc != X86EMUL_CONTINUE) - return rc; - - rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS); - - if (rc != X86EMUL_CONTINUE) - return rc; - - c->eip = temp_eip; - - - if (c->op_bytes == 4) - ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask)); - else if (c->op_bytes == 2) { - ctxt->eflags &= ~0xffff; - ctxt->eflags |= temp_eflags; - } - - ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */ - ctxt->eflags |= EFLG_RESERVED_ONE_MASK; - - return rc; -} - -static inline int emulate_iret(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops* ops) -{ - switch(ctxt->mode) { - case X86EMUL_MODE_REAL: - return emulate_iret_real(ctxt, ops); - case X86EMUL_MODE_VM86: - case X86EMUL_MODE_PROT16: - case X86EMUL_MODE_PROT32: - case X86EMUL_MODE_PROT64: - default: - /* iret from protected mode unimplemented yet */ - return X86EMUL_UNHANDLEABLE; - } -} - -static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops) -{ - struct decode_cache *c = &ctxt->decode; - - return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes); -} + return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes); +} static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt) { @@ -1463,9 +1819,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; - unsigned long *rax = &c->regs[VCPU_REGS_RAX]; - unsigned long *rdx = &c->regs[VCPU_REGS_RDX]; - u8 de = 0; switch (c->modrm_reg) { case 0 ... 1: /* test */ @@ -1477,26 +1830,10 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt, case 3: /* neg */ emulate_1op("neg", c->dst, ctxt->eflags); break; - case 4: /* mul */ - emulate_1op_rax_rdx("mul", c->src, *rax, *rdx, ctxt->eflags); - break; - case 5: /* imul */ - emulate_1op_rax_rdx("imul", c->src, *rax, *rdx, ctxt->eflags); - break; - case 6: /* div */ - emulate_1op_rax_rdx_ex("div", c->src, *rax, *rdx, - ctxt->eflags, de); - break; - case 7: /* idiv */ - emulate_1op_rax_rdx_ex("idiv", c->src, *rax, *rdx, - ctxt->eflags, de); - break; default: - return X86EMUL_UNHANDLEABLE; + return 0; } - if (de) - return emulate_de(ctxt); - return X86EMUL_CONTINUE; + return 1; } static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, @@ -1568,23 +1905,6 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt, return rc; } -static int emulate_load_segment(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, int seg) -{ - struct decode_cache *c = &ctxt->decode; - unsigned short sel; - int rc; - - memcpy(&sel, c->src.valptr + c->op_bytes, 2); - - rc = load_segment_descriptor(ctxt, ops, sel, seg); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->dst.val = c->src.val; - return rc; -} - static inline void setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, struct desc_struct *cs, @@ -1840,15 +2160,9 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { - if (ctxt->perm_ok) - return true; - if (emulator_bad_iopl(ctxt, ops)) if (!emulator_io_port_access_allowed(ctxt, ops, port, len)) return false; - - ctxt->perm_ok = true; - return true; } @@ -1940,7 +2254,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, old_tss_base, err); return ret; } @@ -1950,7 +2264,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, old_tss_base, err); return ret; } @@ -1958,7 +2272,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, new_tss_base, err); return ret; } @@ -1971,7 +2285,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, ctxt->vcpu, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, new_tss_base, err); return ret; } } @@ -2082,7 +2396,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, old_tss_base, err); return ret; } @@ -2092,7 +2406,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, old_tss_base, err); return ret; } @@ -2100,7 +2414,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, new_tss_base, err); return ret; } @@ -2113,7 +2427,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, ctxt->vcpu, &err); if (ret == X86EMUL_PROPAGATE_FAULT) { /* FIXME: need to provide precise fault address */ - emulate_pf(ctxt); + emulate_pf(ctxt, new_tss_base, err); return ret; } } @@ -2180,842 +2494,74 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, else ret = task_switch_16(ctxt, ops, tss_selector, old_tss_sel, old_tss_base, &next_tss_desc); - if (ret != X86EMUL_CONTINUE) - return ret; - - if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) - ctxt->eflags = ctxt->eflags | X86_EFLAGS_NT; - - if (reason != TASK_SWITCH_IRET) { - next_tss_desc.type |= (1 << 1); /* set busy flag */ - write_segment_descriptor(ctxt, ops, tss_selector, - &next_tss_desc); - } - - ops->set_cr(0, ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu); - ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); - ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); - - if (has_error_code) { - struct decode_cache *c = &ctxt->decode; - - c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; - c->lock_prefix = 0; - c->src.val = (unsigned long) error_code; - emulate_push(ctxt, ops); - } - - return ret; -} - -int emulator_task_switch(struct x86_emulate_ctxt *ctxt, - u16 tss_selector, int reason, - bool has_error_code, u32 error_code) -{ - struct x86_emulate_ops *ops = ctxt->ops; - struct decode_cache *c = &ctxt->decode; - int rc; - - c->eip = ctxt->eip; - c->dst.type = OP_NONE; - - rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, - has_error_code, error_code); - - if (rc == X86EMUL_CONTINUE) { - rc = writeback(ctxt, ops); - if (rc == X86EMUL_CONTINUE) - ctxt->eip = c->eip; - } - - return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; -} - -static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base, - int reg, struct operand *op) -{ - struct decode_cache *c = &ctxt->decode; - int df = (ctxt->eflags & EFLG_DF) ? -1 : 1; - - register_address_increment(c, &c->regs[reg], df * op->bytes); - op->addr.mem = register_address(c, base, c->regs[reg]); -} - -static int em_push(struct x86_emulate_ctxt *ctxt) -{ - emulate_push(ctxt, ctxt->ops); - return X86EMUL_CONTINUE; -} - -static int em_das(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - u8 al, old_al; - bool af, cf, old_cf; - - cf = ctxt->eflags & X86_EFLAGS_CF; - al = c->dst.val; - - old_al = al; - old_cf = cf; - cf = false; - af = ctxt->eflags & X86_EFLAGS_AF; - if ((al & 0x0f) > 9 || af) { - al -= 6; - cf = old_cf | (al >= 250); - af = true; - } else { - af = false; - } - if (old_al > 0x99 || old_cf) { - al -= 0x60; - cf = true; - } - - c->dst.val = al; - /* Set PF, ZF, SF */ - c->src.type = OP_IMM; - c->src.val = 0; - c->src.bytes = 1; - emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); - ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF); - if (cf) - ctxt->eflags |= X86_EFLAGS_CF; - if (af) - ctxt->eflags |= X86_EFLAGS_AF; - return X86EMUL_CONTINUE; -} - -static int em_call_far(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - u16 sel, old_cs; - ulong old_eip; - int rc; - - old_cs = ctxt->ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu); - old_eip = c->eip; - - memcpy(&sel, c->src.valptr + c->op_bytes, 2); - if (load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS)) - return X86EMUL_CONTINUE; - - c->eip = 0; - memcpy(&c->eip, c->src.valptr, c->op_bytes); - - c->src.val = old_cs; - emulate_push(ctxt, ctxt->ops); - rc = writeback(ctxt, ctxt->ops); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->src.val = old_eip; - emulate_push(ctxt, ctxt->ops); - rc = writeback(ctxt, ctxt->ops); - if (rc != X86EMUL_CONTINUE) - return rc; - - c->dst.type = OP_NONE; - - return X86EMUL_CONTINUE; -} - -static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - int rc; - - c->dst.type = OP_REG; - c->dst.addr.reg = &c->eip; - c->dst.bytes = c->op_bytes; - rc = emulate_pop(ctxt, ctxt->ops, &c->dst.val, c->op_bytes); - if (rc != X86EMUL_CONTINUE) - return rc; - register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->src.val); - return X86EMUL_CONTINUE; -} - -static int em_imul(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - - emulate_2op_SrcV_nobyte("imul", c->src, c->dst, ctxt->eflags); - return X86EMUL_CONTINUE; -} - -static int em_imul_3op(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - - c->dst.val = c->src2.val; - return em_imul(ctxt); -} - -static int em_cwd(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - - c->dst.type = OP_REG; - c->dst.bytes = c->src.bytes; - c->dst.addr.reg = &c->regs[VCPU_REGS_RDX]; - c->dst.val = ~((c->src.val >> (c->src.bytes * 8 - 1)) - 1); - - return X86EMUL_CONTINUE; -} - -static int em_rdtsc(struct x86_emulate_ctxt *ctxt) -{ - unsigned cpl = ctxt->ops->cpl(ctxt->vcpu); - struct decode_cache *c = &ctxt->decode; - u64 tsc = 0; - - if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD)) { - emulate_gp(ctxt, 0); - return X86EMUL_PROPAGATE_FAULT; - } - ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc); - c->regs[VCPU_REGS_RAX] = (u32)tsc; - c->regs[VCPU_REGS_RDX] = tsc >> 32; - return X86EMUL_CONTINUE; -} - -static int em_mov(struct x86_emulate_ctxt *ctxt) -{ - struct decode_cache *c = &ctxt->decode; - c->dst.val = c->src.val; - return X86EMUL_CONTINUE; -} - -#define D(_y) { .flags = (_y) } -#define N D(0) -#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) } -#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) } -#define I(_f, _e) { .flags = (_f), .u.execute = (_e) } - -#define D2bv(_f) D((_f) | ByteOp), D(_f) -#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e) - -#define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \ - D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \ - D2bv(((_f) & ~Lock) | DstAcc | SrcImm) - - -static struct opcode group1[] = { - X7(D(Lock)), N -}; - -static struct opcode group1A[] = { - D(DstMem | SrcNone | ModRM | Mov | Stack), N, N, N, N, N, N, N, -}; - -static struct opcode group3[] = { - D(DstMem | SrcImm | ModRM), D(DstMem | SrcImm | ModRM), - D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock), - X4(D(SrcMem | ModRM)), -}; - -static struct opcode group4[] = { - D(ByteOp | DstMem | SrcNone | ModRM | Lock), D(ByteOp | DstMem | SrcNone | ModRM | Lock), - N, N, N, N, N, N, -}; - -static struct opcode group5[] = { - D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock), - D(SrcMem | ModRM | Stack), - I(SrcMemFAddr | ModRM | ImplicitOps | Stack, em_call_far), - D(SrcMem | ModRM | Stack), D(SrcMemFAddr | ModRM | ImplicitOps), - D(SrcMem | ModRM | Stack), N, -}; - -static struct group_dual group7 = { { - N, N, D(ModRM | SrcMem | Priv), D(ModRM | SrcMem | Priv), - D(SrcNone | ModRM | DstMem | Mov), N, - D(SrcMem16 | ModRM | Mov | Priv), - D(SrcMem | ModRM | ByteOp | Priv | NoAccess), -}, { - D(SrcNone | ModRM | Priv), N, N, D(SrcNone | ModRM | Priv), - D(SrcNone | ModRM | DstMem | Mov), N, - D(SrcMem16 | ModRM | Mov | Priv), N, -} }; - -static struct opcode group8[] = { - N, N, N, N, - D(DstMem | SrcImmByte | ModRM), D(DstMem | SrcImmByte | ModRM | Lock), - D(DstMem | SrcImmByte | ModRM | Lock), D(DstMem | SrcImmByte | ModRM | Lock), -}; - -static struct group_dual group9 = { { - N, D(DstMem64 | ModRM | Lock), N, N, N, N, N, N, -}, { - N, N, N, N, N, N, N, N, -} }; - -static struct opcode group11[] = { - I(DstMem | SrcImm | ModRM | Mov, em_mov), X7(D(Undefined)), -}; - -static struct opcode opcode_table[256] = { - /* 0x00 - 0x07 */ - D6ALU(Lock), - D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), - /* 0x08 - 0x0F */ - D6ALU(Lock), - D(ImplicitOps | Stack | No64), N, - /* 0x10 - 0x17 */ - D6ALU(Lock), - D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), - /* 0x18 - 0x1F */ - D6ALU(Lock), - D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), - /* 0x20 - 0x27 */ - D6ALU(Lock), N, N, - /* 0x28 - 0x2F */ - D6ALU(Lock), N, I(ByteOp | DstAcc | No64, em_das), - /* 0x30 - 0x37 */ - D6ALU(Lock), N, N, - /* 0x38 - 0x3F */ - D6ALU(0), N, N, - /* 0x40 - 0x4F */ - X16(D(DstReg)), - /* 0x50 - 0x57 */ - X8(I(SrcReg | Stack, em_push)), - /* 0x58 - 0x5F */ - X8(D(DstReg | Stack)), - /* 0x60 - 0x67 */ - D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), - N, D(DstReg | SrcMem32 | ModRM | Mov) /* movsxd (x86/64) */ , - N, N, N, N, - /* 0x68 - 0x6F */ - I(SrcImm | Mov | Stack, em_push), - I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), - I(SrcImmByte | Mov | Stack, em_push), - I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), - D2bv(DstDI | Mov | String), /* insb, insw/insd */ - D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */ - /* 0x70 - 0x7F */ - X16(D(SrcImmByte)), - /* 0x80 - 0x87 */ - G(ByteOp | DstMem | SrcImm | ModRM | Group, group1), - G(DstMem | SrcImm | ModRM | Group, group1), - G(ByteOp | DstMem | SrcImm | ModRM | No64 | Group, group1), - G(DstMem | SrcImmByte | ModRM | Group, group1), - D2bv(DstMem | SrcReg | ModRM), D2bv(DstMem | SrcReg | ModRM | Lock), - /* 0x88 - 0x8F */ - I2bv(DstMem | SrcReg | ModRM | Mov, em_mov), - I2bv(DstReg | SrcMem | ModRM | Mov, em_mov), - D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg), - D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A), - /* 0x90 - 0x97 */ - X8(D(SrcAcc | DstReg)), - /* 0x98 - 0x9F */ - D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd), - I(SrcImmFAddr | No64, em_call_far), N, - D(ImplicitOps | Stack), D(ImplicitOps | Stack), N, N, - /* 0xA0 - 0xA7 */ - I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov), - I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov), - I2bv(SrcSI | DstDI | Mov | String, em_mov), - D2bv(SrcSI | DstDI | String), - /* 0xA8 - 0xAF */ - D2bv(DstAcc | SrcImm), - I2bv(SrcAcc | DstDI | Mov | String, em_mov), - I2bv(SrcSI | DstAcc | Mov | String, em_mov), - D2bv(SrcAcc | DstDI | String), - /* 0xB0 - 0xB7 */ - X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)), - /* 0xB8 - 0xBF */ - X8(I(DstReg | SrcImm | Mov, em_mov)), - /* 0xC0 - 0xC7 */ - D2bv(DstMem | SrcImmByte | ModRM), - I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm), - D(ImplicitOps | Stack), - D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64), - G(ByteOp, group11), G(0, group11), - /* 0xC8 - 0xCF */ - N, N, N, D(ImplicitOps | Stack), - D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps), - /* 0xD0 - 0xD7 */ - D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM), - N, N, N, N, - /* 0xD8 - 0xDF */ - N, N, N, N, N, N, N, N, - /* 0xE0 - 0xE7 */ - X4(D(SrcImmByte)), - D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte), - /* 0xE8 - 0xEF */ - D(SrcImm | Stack), D(SrcImm | ImplicitOps), - D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps), - D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps), - /* 0xF0 - 0xF7 */ - N, N, N, N, - D(ImplicitOps | Priv), D(ImplicitOps), G(ByteOp, group3), G(0, group3), - /* 0xF8 - 0xFF */ - D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), - D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5), -}; - -static struct opcode twobyte_table[256] = { - /* 0x00 - 0x0F */ - N, GD(0, &group7), N, N, - N, D(ImplicitOps), D(ImplicitOps | Priv), N, - D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N, - N, D(ImplicitOps | ModRM), N, N, - /* 0x10 - 0x1F */ - N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N, - /* 0x20 - 0x2F */ - D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264), - D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264), - N, N, N, N, - N, N, N, N, N, N, N, N, - /* 0x30 - 0x3F */ - D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc), - D(ImplicitOps | Priv), N, - D(ImplicitOps), D(ImplicitOps | Priv), N, N, - N, N, N, N, N, N, N, N, - /* 0x40 - 0x4F */ - X16(D(DstReg | SrcMem | ModRM | Mov)), - /* 0x50 - 0x5F */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - /* 0x60 - 0x6F */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - /* 0x70 - 0x7F */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - /* 0x80 - 0x8F */ - X16(D(SrcImm)), - /* 0x90 - 0x9F */ - X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)), - /* 0xA0 - 0xA7 */ - D(ImplicitOps | Stack), D(ImplicitOps | Stack), - N, D(DstMem | SrcReg | ModRM | BitOp), - D(DstMem | SrcReg | Src2ImmByte | ModRM), - D(DstMem | SrcReg | Src2CL | ModRM), N, N, - /* 0xA8 - 0xAF */ - D(ImplicitOps | Stack), D(ImplicitOps | Stack), - N, D(DstMem | SrcReg | ModRM | BitOp | Lock), - D(DstMem | SrcReg | Src2ImmByte | ModRM), - D(DstMem | SrcReg | Src2CL | ModRM), - D(ModRM), I(DstReg | SrcMem | ModRM, em_imul), - /* 0xB0 - 0xB7 */ - D2bv(DstMem | SrcReg | ModRM | Lock), - D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock), - D(DstReg | SrcMemFAddr | ModRM), D(DstReg | SrcMemFAddr | ModRM), - D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), - /* 0xB8 - 0xBF */ - N, N, - G(BitOp, group8), D(DstMem | SrcReg | ModRM | BitOp | Lock), - D(DstReg | SrcMem | ModRM), D(DstReg | SrcMem | ModRM), - D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), - /* 0xC0 - 0xCF */ - D2bv(DstMem | SrcReg | ModRM | Lock), - N, D(DstMem | SrcReg | ModRM | Mov), - N, N, N, GD(0, &group9), - N, N, N, N, N, N, N, N, - /* 0xD0 - 0xDF */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - /* 0xE0 - 0xEF */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - /* 0xF0 - 0xFF */ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N -}; - -#undef D -#undef N -#undef G -#undef GD -#undef I - -#undef D2bv -#undef I2bv -#undef D6ALU - -static unsigned imm_size(struct decode_cache *c) -{ - unsigned size; - - size = (c->d & ByteOp) ? 1 : c->op_bytes; - if (size == 8) - size = 4; - return size; -} - -static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op, - unsigned size, bool sign_extension) -{ - struct decode_cache *c = &ctxt->decode; - struct x86_emulate_ops *ops = ctxt->ops; - int rc = X86EMUL_CONTINUE; - - op->type = OP_IMM; - op->bytes = size; - op->addr.mem = c->eip; - /* NB. Immediates are sign-extended as necessary. */ - switch (op->bytes) { - case 1: - op->val = insn_fetch(s8, 1, c->eip); - break; - case 2: - op->val = insn_fetch(s16, 2, c->eip); - break; - case 4: - op->val = insn_fetch(s32, 4, c->eip); - break; - } - if (!sign_extension) { - switch (op->bytes) { - case 1: - op->val &= 0xff; - break; - case 2: - op->val &= 0xffff; - break; - case 4: - op->val &= 0xffffffff; - break; - } - } -done: - return rc; -} - -int -x86_decode_insn(struct x86_emulate_ctxt *ctxt) -{ - struct x86_emulate_ops *ops = ctxt->ops; - struct decode_cache *c = &ctxt->decode; - int rc = X86EMUL_CONTINUE; - int mode = ctxt->mode; - int def_op_bytes, def_ad_bytes, dual, goffset; - struct opcode opcode, *g_mod012, *g_mod3; - struct operand memop = { .type = OP_NONE }; - - c->eip = ctxt->eip; - c->fetch.start = c->fetch.end = c->eip; - ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS); - - switch (mode) { - case X86EMUL_MODE_REAL: - case X86EMUL_MODE_VM86: - case X86EMUL_MODE_PROT16: - def_op_bytes = def_ad_bytes = 2; - break; - case X86EMUL_MODE_PROT32: - def_op_bytes = def_ad_bytes = 4; - break; -#ifdef CONFIG_X86_64 - case X86EMUL_MODE_PROT64: - def_op_bytes = 4; - def_ad_bytes = 8; - break; -#endif - default: - return -1; - } - - c->op_bytes = def_op_bytes; - c->ad_bytes = def_ad_bytes; - - /* Legacy prefixes. */ - for (;;) { - switch (c->b = insn_fetch(u8, 1, c->eip)) { - case 0x66: /* operand-size override */ - /* switch between 2/4 bytes */ - c->op_bytes = def_op_bytes ^ 6; - break; - case 0x67: /* address-size override */ - if (mode == X86EMUL_MODE_PROT64) - /* switch between 4/8 bytes */ - c->ad_bytes = def_ad_bytes ^ 12; - else - /* switch between 2/4 bytes */ - c->ad_bytes = def_ad_bytes ^ 6; - break; - case 0x26: /* ES override */ - case 0x2e: /* CS override */ - case 0x36: /* SS override */ - case 0x3e: /* DS override */ - set_seg_override(c, (c->b >> 3) & 3); - break; - case 0x64: /* FS override */ - case 0x65: /* GS override */ - set_seg_override(c, c->b & 7); - break; - case 0x40 ... 0x4f: /* REX */ - if (mode != X86EMUL_MODE_PROT64) - goto done_prefixes; - c->rex_prefix = c->b; - continue; - case 0xf0: /* LOCK */ - c->lock_prefix = 1; - break; - case 0xf2: /* REPNE/REPNZ */ - c->rep_prefix = REPNE_PREFIX; - break; - case 0xf3: /* REP/REPE/REPZ */ - c->rep_prefix = REPE_PREFIX; - break; - default: - goto done_prefixes; - } - - /* Any legacy prefix after a REX prefix nullifies its effect. */ - - c->rex_prefix = 0; - } - -done_prefixes: - - /* REX prefix. */ - if (c->rex_prefix & 8) - c->op_bytes = 8; /* REX.W */ - - /* Opcode byte(s). */ - opcode = opcode_table[c->b]; - /* Two-byte opcode? */ - if (c->b == 0x0f) { - c->twobyte = 1; - c->b = insn_fetch(u8, 1, c->eip); - opcode = twobyte_table[c->b]; - } - c->d = opcode.flags; - - if (c->d & Group) { - dual = c->d & GroupDual; - c->modrm = insn_fetch(u8, 1, c->eip); - --c->eip; - - if (c->d & GroupDual) { - g_mod012 = opcode.u.gdual->mod012; - g_mod3 = opcode.u.gdual->mod3; - } else - g_mod012 = g_mod3 = opcode.u.group; - - c->d &= ~(Group | GroupDual); - - goffset = (c->modrm >> 3) & 7; - - if ((c->modrm >> 6) == 3) - opcode = g_mod3[goffset]; - else - opcode = g_mod012[goffset]; - c->d |= opcode.flags; - } - - c->execute = opcode.u.execute; - - /* Unrecognised? */ - if (c->d == 0 || (c->d & Undefined)) { - DPRINTF("Cannot emulate %02x\n", c->b); - return -1; - } - - if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) - c->op_bytes = 8; - - if (c->d & Op3264) { - if (mode == X86EMUL_MODE_PROT64) - c->op_bytes = 8; - else - c->op_bytes = 4; - } - - /* ModRM and SIB bytes. */ - if (c->d & ModRM) { - rc = decode_modrm(ctxt, ops, &memop); - if (!c->has_seg_override) - set_seg_override(c, c->modrm_seg); - } else if (c->d & MemAbs) - rc = decode_abs(ctxt, ops, &memop); - if (rc != X86EMUL_CONTINUE) - goto done; - - if (!c->has_seg_override) - set_seg_override(c, VCPU_SREG_DS); - - if (memop.type == OP_MEM && !(!c->twobyte && c->b == 0x8d)) - memop.addr.mem += seg_override_base(ctxt, ops, c); - - if (memop.type == OP_MEM && c->ad_bytes != 8) - memop.addr.mem = (u32)memop.addr.mem; - - if (memop.type == OP_MEM && c->rip_relative) - memop.addr.mem += c->eip; - - /* - * Decode and fetch the source operand: register, memory - * or immediate. - */ - switch (c->d & SrcMask) { - case SrcNone: - break; - case SrcReg: - decode_register_operand(&c->src, c, 0); - break; - case SrcMem16: - memop.bytes = 2; - goto srcmem_common; - case SrcMem32: - memop.bytes = 4; - goto srcmem_common; - case SrcMem: - memop.bytes = (c->d & ByteOp) ? 1 : - c->op_bytes; - srcmem_common: - c->src = memop; - break; - case SrcImmU16: - rc = decode_imm(ctxt, &c->src, 2, false); - break; - case SrcImm: - rc = decode_imm(ctxt, &c->src, imm_size(c), true); - break; - case SrcImmU: - rc = decode_imm(ctxt, &c->src, imm_size(c), false); - break; - case SrcImmByte: - rc = decode_imm(ctxt, &c->src, 1, true); - break; - case SrcImmUByte: - rc = decode_imm(ctxt, &c->src, 1, false); - break; - case SrcAcc: - c->src.type = OP_REG; - c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - c->src.addr.reg = &c->regs[VCPU_REGS_RAX]; - fetch_register_operand(&c->src); - break; - case SrcOne: - c->src.bytes = 1; - c->src.val = 1; - break; - case SrcSI: - c->src.type = OP_MEM; - c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - c->src.addr.mem = - register_address(c, seg_override_base(ctxt, ops, c), - c->regs[VCPU_REGS_RSI]); - c->src.val = 0; - break; - case SrcImmFAddr: - c->src.type = OP_IMM; - c->src.addr.mem = c->eip; - c->src.bytes = c->op_bytes + 2; - insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip); - break; - case SrcMemFAddr: - memop.bytes = c->op_bytes + 2; - goto srcmem_common; - break; + if (ret != X86EMUL_CONTINUE) + return ret; + + if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) + ctxt->eflags = ctxt->eflags | X86_EFLAGS_NT; + + if (reason != TASK_SWITCH_IRET) { + next_tss_desc.type |= (1 << 1); /* set busy flag */ + write_segment_descriptor(ctxt, ops, tss_selector, + &next_tss_desc); } - if (rc != X86EMUL_CONTINUE) - goto done; + ops->set_cr(0, ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu); + ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); + ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); - /* - * Decode and fetch the second source operand: register, memory - * or immediate. - */ - switch (c->d & Src2Mask) { - case Src2None: - break; - case Src2CL: - c->src2.bytes = 1; - c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8; - break; - case Src2ImmByte: - rc = decode_imm(ctxt, &c->src2, 1, true); - break; - case Src2One: - c->src2.bytes = 1; - c->src2.val = 1; - break; - case Src2Imm: - rc = decode_imm(ctxt, &c->src2, imm_size(c), true); - break; + if (has_error_code) { + struct decode_cache *c = &ctxt->decode; + + c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; + c->lock_prefix = 0; + c->src.val = (unsigned long) error_code; + emulate_push(ctxt, ops); } - if (rc != X86EMUL_CONTINUE) - goto done; + return ret; +} - /* Decode and fetch the destination operand: register or memory. */ - switch (c->d & DstMask) { - case DstReg: - decode_register_operand(&c->dst, c, - c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); - break; - case DstImmUByte: - c->dst.type = OP_IMM; - c->dst.addr.mem = c->eip; - c->dst.bytes = 1; - c->dst.val = insn_fetch(u8, 1, c->eip); - break; - case DstMem: - case DstMem64: - c->dst = memop; - if ((c->d & DstMask) == DstMem64) - c->dst.bytes = 8; - else - c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - if (c->d & BitOp) - fetch_bit_operand(c); - c->dst.orig_val = c->dst.val; - break; - case DstAcc: - c->dst.type = OP_REG; - c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - c->dst.addr.reg = &c->regs[VCPU_REGS_RAX]; - fetch_register_operand(&c->dst); - c->dst.orig_val = c->dst.val; - break; - case DstDI: - c->dst.type = OP_MEM; - c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; - c->dst.addr.mem = - register_address(c, es_base(ctxt, ops), - c->regs[VCPU_REGS_RDI]); - c->dst.val = 0; - break; - case ImplicitOps: - /* Special instructions do their own operand decoding. */ - default: - c->dst.type = OP_NONE; /* Disable writeback. */ - return 0; +int emulator_task_switch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + u16 tss_selector, int reason, + bool has_error_code, u32 error_code) +{ + struct decode_cache *c = &ctxt->decode; + int rc; + + c->eip = ctxt->eip; + c->dst.type = OP_NONE; + + rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, + has_error_code, error_code); + + if (rc == X86EMUL_CONTINUE) { + rc = writeback(ctxt, ops); + if (rc == X86EMUL_CONTINUE) + ctxt->eip = c->eip; } -done: return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; } -static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) +static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base, + int reg, struct operand *op) { struct decode_cache *c = &ctxt->decode; + int df = (ctxt->eflags & EFLG_DF) ? -1 : 1; - /* The second termination condition only applies for REPE - * and REPNE. Test if the repeat string operation prefix is - * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the - * corresponding termination condition according to: - * - if REPE/REPZ and ZF = 0 then done - * - if REPNE/REPNZ and ZF = 1 then done - */ - if (((c->b == 0xa6) || (c->b == 0xa7) || - (c->b == 0xae) || (c->b == 0xaf)) - && (((c->rep_prefix == REPE_PREFIX) && - ((ctxt->eflags & EFLG_ZF) == 0)) - || ((c->rep_prefix == REPNE_PREFIX) && - ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)))) - return true; - - return false; + register_address_increment(c, &c->regs[reg], df * op->bytes); + op->ptr = (unsigned long *)register_address(c, base, c->regs[reg]); } int -x86_emulate_insn(struct x86_emulate_ctxt *ctxt) +x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - struct x86_emulate_ops *ops = ctxt->ops; u64 msr_data; struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; int saved_dst_type = c->dst.type; - int irq; /* Used for int 3, int, and into */ ctxt->decode.mem_read.pos = 0; @@ -3030,11 +2576,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { - emulate_ud(ctxt); - goto done; - } - /* Privileged instruction can be executed only in CPL=0 */ if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) { emulate_gp(ctxt, 0); @@ -3042,15 +2583,35 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } if (c->rep_prefix && (c->d & String)) { + ctxt->restart = true; /* All REP prefixes have the same first termination condition */ if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { + string_done: + ctxt->restart = false; ctxt->eip = c->eip; goto done; } + /* The second termination condition only applies for REPE + * and REPNE. Test if the repeat string operation prefix is + * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the + * corresponding termination condition according to: + * - if REPE/REPZ and ZF = 0 then done + * - if REPNE/REPNZ and ZF = 1 then done + */ + if ((c->b == 0xa6) || (c->b == 0xa7) || + (c->b == 0xae) || (c->b == 0xaf)) { + if ((c->rep_prefix == REPE_PREFIX) && + ((ctxt->eflags & EFLG_ZF) == 0)) + goto string_done; + if ((c->rep_prefix == REPNE_PREFIX) && + ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) + goto string_done; + } + c->eip = ctxt->eip; } - if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) { - rc = read_emulated(ctxt, ops, c->src.addr.mem, + if (c->src.type == OP_MEM) { + rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr, c->src.valptr, c->src.bytes); if (rc != X86EMUL_CONTINUE) goto done; @@ -3058,7 +2619,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } if (c->src2.type == OP_MEM) { - rc = read_emulated(ctxt, ops, c->src2.addr.mem, + rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr, &c->src2.val, c->src2.bytes); if (rc != X86EMUL_CONTINUE) goto done; @@ -3070,7 +2631,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) if ((c->dst.type == OP_MEM) && !(c->d & Mov)) { /* optimisation - avoid slow emulated read if Mov */ - rc = read_emulated(ctxt, ops, c->dst.addr.mem, + rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr, &c->dst.val, c->dst.bytes); if (rc != X86EMUL_CONTINUE) goto done; @@ -3079,13 +2640,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) special_insn: - if (c->execute) { - rc = c->execute(ctxt); - if (rc != X86EMUL_CONTINUE) - goto done; - goto writeback; - } - if (c->twobyte) goto twobyte_insn; @@ -3099,6 +2653,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x07: /* pop es */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x08 ... 0x0d: or: /* or */ @@ -3116,6 +2672,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x17: /* pop ss */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x18 ... 0x1d: sbb: /* sbb */ @@ -3126,6 +2684,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x1f: /* pop ds */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x20 ... 0x25: and: /* and */ @@ -3149,29 +2709,58 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0x48 ... 0x4f: /* dec r16/r32 */ emulate_1op("dec", c->dst, ctxt->eflags); break; + case 0x50 ... 0x57: /* push reg */ + emulate_push(ctxt, ops); + break; case 0x58 ... 0x5f: /* pop reg */ pop_instruction: rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x60: /* pusha */ rc = emulate_pusha(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x61: /* popa */ rc = emulate_popa(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x63: /* movsxd */ if (ctxt->mode != X86EMUL_MODE_PROT64) goto cannot_emulate; c->dst.val = (s32) c->src.val; break; + case 0x68: /* push imm */ + case 0x6a: /* push imm8 */ + emulate_push(ctxt, ops); + break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ - c->src.val = c->regs[VCPU_REGS_RDX]; - goto do_io_in; + c->dst.bytes = min(c->dst.bytes, 4u); + if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], + c->dst.bytes)) { + emulate_gp(ctxt, 0); + goto done; + } + if (!pio_in_emulated(ctxt, ops, c->dst.bytes, + c->regs[VCPU_REGS_RDX], &c->dst.val)) + goto done; /* IO is needed, skip writeback */ + break; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ - c->dst.val = c->regs[VCPU_REGS_RDX]; - goto do_io_out; + c->src.bytes = min(c->src.bytes, 4u); + if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], + c->src.bytes)) { + emulate_gp(ctxt, 0); + goto done; + } + ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX], + &c->src.val, 1, ctxt->vcpu); + + c->dst.type = OP_NONE; /* nothing to writeback */ break; case 0x70 ... 0x7f: /* jcc (short) */ if (test_cc(c->b, ctxt->eflags)) @@ -3204,15 +2793,29 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0x86 ... 0x87: /* xchg */ xchg: /* Write back the register source. */ - c->src.val = c->dst.val; - write_register_operand(&c->src); + switch (c->dst.bytes) { + case 1: + *(u8 *) c->src.ptr = (u8) c->dst.val; + break; + case 2: + *(u16 *) c->src.ptr = (u16) c->dst.val; + break; + case 4: + *c->src.ptr = (u32) c->dst.val; + break; /* 64b reg: zero-extend */ + case 8: + *c->src.ptr = c->dst.val; + break; + } /* * Write back the memory destination with implicit LOCK * prefix. */ - c->dst.val = c->src.orig_val; + c->dst.val = c->src.val; c->lock_prefix = 1; break; + case 0x88 ... 0x8b: /* mov */ + goto mov; case 0x8c: /* mov r/m, sreg */ if (c->modrm_reg > VCPU_SREG_GS) { emulate_ud(ctxt); @@ -3221,7 +2824,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu); break; case 0x8d: /* lea r16/r32, m */ - c->dst.val = c->src.addr.mem; + c->dst.val = c->modrm_ea; break; case 0x8e: { /* mov seg, r/m16 */ uint16_t sel; @@ -3244,87 +2847,76 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } case 0x8f: /* pop (sole member of Grp1a) */ rc = emulate_grp1a(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; - case 0x90 ... 0x97: /* nop / xchg reg, rax */ - if (c->dst.addr.reg == &c->regs[VCPU_REGS_RAX]) + case 0x90: /* nop / xchg r8,rax */ + if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) { + c->dst.type = OP_NONE; /* nop */ break; - goto xchg; - case 0x98: /* cbw/cwde/cdqe */ - switch (c->op_bytes) { - case 2: c->dst.val = (s8)c->dst.val; break; - case 4: c->dst.val = (s16)c->dst.val; break; - case 8: c->dst.val = (s32)c->dst.val; break; } - break; + case 0x91 ... 0x97: /* xchg reg,rax */ + c->src.type = OP_REG; + c->src.bytes = c->op_bytes; + c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX]; + c->src.val = *(c->src.ptr); + goto xchg; case 0x9c: /* pushf */ c->src.val = (unsigned long) ctxt->eflags; emulate_push(ctxt, ops); break; case 0x9d: /* popf */ c->dst.type = OP_REG; - c->dst.addr.reg = &ctxt->eflags; + c->dst.ptr = (unsigned long *) &ctxt->eflags; c->dst.bytes = c->op_bytes; rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes); + if (rc != X86EMUL_CONTINUE) + goto done; break; + case 0xa0 ... 0xa3: /* mov */ + case 0xa4 ... 0xa5: /* movs */ + goto mov; case 0xa6 ... 0xa7: /* cmps */ c->dst.type = OP_NONE; /* Disable writeback. */ - DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.addr.mem, c->dst.addr.mem); + DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr); goto cmp; case 0xa8 ... 0xa9: /* test ax, imm */ goto test; + case 0xaa ... 0xab: /* stos */ + c->dst.val = c->regs[VCPU_REGS_RAX]; + break; + case 0xac ... 0xad: /* lods */ + goto mov; case 0xae ... 0xaf: /* scas */ - goto cmp; + DPRINTF("Urk! I don't handle SCAS.\n"); + goto cannot_emulate; + case 0xb0 ... 0xbf: /* mov r, imm */ + goto mov; case 0xc0 ... 0xc1: emulate_grp2(ctxt); break; case 0xc3: /* ret */ c->dst.type = OP_REG; - c->dst.addr.reg = &c->eip; + c->dst.ptr = &c->eip; c->dst.bytes = c->op_bytes; goto pop_instruction; - case 0xc4: /* les */ - rc = emulate_load_segment(ctxt, ops, VCPU_SREG_ES); - break; - case 0xc5: /* lds */ - rc = emulate_load_segment(ctxt, ops, VCPU_SREG_DS); + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + mov: + c->dst.val = c->src.val; break; case 0xcb: /* ret far */ rc = emulate_ret_far(ctxt, ops); - break; - case 0xcc: /* int3 */ - irq = 3; - goto do_interrupt; - case 0xcd: /* int n */ - irq = c->src.val; - do_interrupt: - rc = emulate_int(ctxt, ops, irq); - break; - case 0xce: /* into */ - if (ctxt->eflags & EFLG_OF) { - irq = 4; - goto do_interrupt; - } - break; - case 0xcf: /* iret */ - rc = emulate_iret(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xd0 ... 0xd1: /* Grp2 */ + c->src.val = 1; emulate_grp2(ctxt); break; case 0xd2 ... 0xd3: /* Grp2 */ c->src.val = c->regs[VCPU_REGS_RCX]; emulate_grp2(ctxt); break; - case 0xe0 ... 0xe2: /* loop/loopz/loopnz */ - register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); - if (address_mask(c, c->regs[VCPU_REGS_RCX]) != 0 && - (c->b == 0xe2 || test_cc(c->b ^ 0x5, ctxt->eflags))) - jmp_rel(c, c->src.val); - break; - case 0xe3: /* jcxz/jecxz/jrcxz */ - if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) - jmp_rel(c, c->src.val); - break; case 0xe4: /* inb */ case 0xe5: /* in */ goto do_io_in; @@ -3372,16 +2964,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xee: /* out dx,al */ case 0xef: /* out dx,(e/r)ax */ - c->dst.val = c->regs[VCPU_REGS_RDX]; + c->src.val = c->regs[VCPU_REGS_RDX]; do_io_out: - c->src.bytes = min(c->src.bytes, 4u); - if (!emulator_io_permited(ctxt, ops, c->dst.val, - c->src.bytes)) { + c->dst.bytes = min(c->dst.bytes, 4u); + if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { emulate_gp(ctxt, 0); goto done; } - ops->pio_out_emulated(c->src.bytes, c->dst.val, - &c->src.val, 1, ctxt->vcpu); + ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1, + ctxt->vcpu); c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xf4: /* hlt */ @@ -3390,22 +2981,24 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0xf5: /* cmc */ /* complement carry flag from eflags reg */ ctxt->eflags ^= EFLG_CF; + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xf6 ... 0xf7: /* Grp3 */ - rc = emulate_grp3(ctxt, ops); + if (!emulate_grp3(ctxt, ops)) + goto cannot_emulate; break; case 0xf8: /* clc */ ctxt->eflags &= ~EFLG_CF; - break; - case 0xf9: /* stc */ - ctxt->eflags |= EFLG_CF; + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfa: /* cli */ if (emulator_bad_iopl(ctxt, ops)) { emulate_gp(ctxt, 0); goto done; - } else + } else { ctxt->eflags &= ~X86_EFLAGS_IF; + c->dst.type = OP_NONE; /* Disable writeback. */ + } break; case 0xfb: /* sti */ if (emulator_bad_iopl(ctxt, ops)) { @@ -3414,29 +3007,29 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } else { ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; ctxt->eflags |= X86_EFLAGS_IF; + c->dst.type = OP_NONE; /* Disable writeback. */ } break; case 0xfc: /* cld */ ctxt->eflags &= ~EFLG_DF; + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfd: /* std */ ctxt->eflags |= EFLG_DF; + c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfe: /* Grp4 */ grp45: rc = emulate_grp45(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xff: /* Grp5 */ if (c->modrm_reg == 5) goto jump_far; goto grp45; - default: - goto cannot_emulate; } - if (rc != X86EMUL_CONTINUE) - goto done; - writeback: rc = writeback(ctxt, ops); if (rc != X86EMUL_CONTINUE) @@ -3457,32 +3050,25 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) &c->dst); if (c->rep_prefix && (c->d & String)) { - struct read_cache *r = &ctxt->decode.io_read; + struct read_cache *rc = &ctxt->decode.io_read; register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); - - if (!string_insn_completed(ctxt)) { - /* - * Re-enter guest when pio read ahead buffer is empty - * or, if it is not used, after each 1024 iteration. - */ - if ((r->end != 0 || c->regs[VCPU_REGS_RCX] & 0x3ff) && - (r->end == 0 || r->end != r->pos)) { - /* - * Reset read cache. Usually happens before - * decode, but since instruction is restarted - * we have to do it here. - */ - ctxt->decode.mem_read.end = 0; - return EMULATION_RESTART; - } - goto done; /* skip rip writeback */ - } + /* + * Re-enter guest when pio read ahead buffer is empty or, + * if it is not used, after each 1024 iteration. + */ + if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) || + (rc->end != 0 && rc->end == rc->pos)) + ctxt->restart = false; } - + /* + * reset read cache here in case string instruction is restared + * without decoding + */ + ctxt->decode.mem_read.end = 0; ctxt->eip = c->eip; done: - return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; + return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; twobyte_insn: switch (c->b) { @@ -3505,7 +3091,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) c->dst.type = OP_NONE; break; case 2: /* lgdt */ - rc = read_descriptor(ctxt, ops, c->src.addr.mem, + rc = read_descriptor(ctxt, ops, c->src.ptr, &size, &address, c->op_bytes); if (rc != X86EMUL_CONTINUE) goto done; @@ -3518,12 +3104,14 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) switch (c->modrm_rm) { case 1: rc = kvm_fix_hypercall(ctxt->vcpu); + if (rc != X86EMUL_CONTINUE) + goto done; break; default: goto cannot_emulate; } } else { - rc = read_descriptor(ctxt, ops, c->src.addr.mem, + rc = read_descriptor(ctxt, ops, c->src.ptr, &size, &address, c->op_bytes); if (rc != X86EMUL_CONTINUE) @@ -3538,7 +3126,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) c->dst.val = ops->get_cr(0, ctxt->vcpu); break; case 6: /* lmsw */ - ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0eul) | + ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) | (c->src.val & 0x0f), ctxt->vcpu); c->dst.type = OP_NONE; break; @@ -3546,7 +3134,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) emulate_ud(ctxt); goto done; case 7: /* invlpg*/ - emulate_invlpg(ctxt->vcpu, c->src.addr.mem); + emulate_invlpg(ctxt->vcpu, c->modrm_ea); /* Disable writeback. */ c->dst.type = OP_NONE; break; @@ -3556,16 +3144,23 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0x05: /* syscall */ rc = emulate_syscall(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; + else + goto writeback; break; case 0x06: emulate_clts(ctxt->vcpu); + c->dst.type = OP_NONE; break; case 0x09: /* wbinvd */ kvm_emulate_wbinvd(ctxt->vcpu); + c->dst.type = OP_NONE; break; case 0x08: /* invd */ case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ + c->dst.type = OP_NONE; break; case 0x20: /* mov cr, reg */ switch (c->modrm_reg) { @@ -3575,7 +3170,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) emulate_ud(ctxt); goto done; } - c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); + c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu); + c->dst.type = OP_NONE; /* no writeback */ break; case 0x21: /* mov from dr to reg */ if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) && @@ -3583,10 +3179,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) emulate_ud(ctxt); goto done; } - ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu); + ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu); + c->dst.type = OP_NONE; /* no writeback */ break; case 0x22: /* mov reg, cr */ - if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) { + if (ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu)) { emulate_gp(ctxt, 0); goto done; } @@ -3599,7 +3196,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if (ops->set_dr(c->modrm_reg, c->src.val & + if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] & ((ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U), ctxt->vcpu) < 0) { /* #UD condition is already handled by the code above */ @@ -3618,6 +3215,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } rc = X86EMUL_CONTINUE; + c->dst.type = OP_NONE; break; case 0x32: /* rdmsr */ @@ -3629,12 +3227,21 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) c->regs[VCPU_REGS_RDX] = msr_data >> 32; } rc = X86EMUL_CONTINUE; + c->dst.type = OP_NONE; break; case 0x34: /* sysenter */ rc = emulate_sysenter(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; + else + goto writeback; break; case 0x35: /* sysexit */ rc = emulate_sysexit(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; + else + goto writeback; break; case 0x40 ... 0x4f: /* cmov */ c->dst.val = c->dst.orig_val = c->src.val; @@ -3644,15 +3251,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) case 0x80 ... 0x8f: /* jnz rel, etc*/ if (test_cc(c->b, ctxt->eflags)) jmp_rel(c, c->src.val); - break; - case 0x90 ... 0x9f: /* setcc r/m8 */ - c->dst.val = test_cc(c->b, ctxt->eflags); + c->dst.type = OP_NONE; break; case 0xa0: /* push fs */ emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); break; case 0xa1: /* pop fs */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xa3: bt: /* bt */ @@ -3670,9 +3277,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xa9: /* pop gs */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xab: bts: /* bts */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags); break; case 0xac: /* shrd imm8, r, r/m */ @@ -3695,22 +3306,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } else { /* Failure: write the value we saw to EAX. */ c->dst.type = OP_REG; - c->dst.addr.reg = (unsigned long *)&c->regs[VCPU_REGS_RAX]; + c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; } break; - case 0xb2: /* lss */ - rc = emulate_load_segment(ctxt, ops, VCPU_SREG_SS); - break; case 0xb3: btr: /* btr */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; emulate_2op_SrcV_nobyte("btr", c->src, c->dst, ctxt->eflags); break; - case 0xb4: /* lfs */ - rc = emulate_load_segment(ctxt, ops, VCPU_SREG_FS); - break; - case 0xb5: /* lgs */ - rc = emulate_load_segment(ctxt, ops, VCPU_SREG_GS); - break; case 0xb6 ... 0xb7: /* movzx */ c->dst.bytes = c->op_bytes; c->dst.val = (c->d & ByteOp) ? (u8) c->src.val @@ -3730,43 +3334,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xbb: btc: /* btc */ + /* only subword offset */ + c->src.val &= (c->dst.bytes << 3) - 1; emulate_2op_SrcV_nobyte("btc", c->src, c->dst, ctxt->eflags); break; - case 0xbc: { /* bsf */ - u8 zf; - __asm__ ("bsf %2, %0; setz %1" - : "=r"(c->dst.val), "=q"(zf) - : "r"(c->src.val)); - ctxt->eflags &= ~X86_EFLAGS_ZF; - if (zf) { - ctxt->eflags |= X86_EFLAGS_ZF; - c->dst.type = OP_NONE; /* Disable writeback. */ - } - break; - } - case 0xbd: { /* bsr */ - u8 zf; - __asm__ ("bsr %2, %0; setz %1" - : "=r"(c->dst.val), "=q"(zf) - : "r"(c->src.val)); - ctxt->eflags &= ~X86_EFLAGS_ZF; - if (zf) { - ctxt->eflags |= X86_EFLAGS_ZF; - c->dst.type = OP_NONE; /* Disable writeback. */ - } - break; - } case 0xbe ... 0xbf: /* movsx */ c->dst.bytes = c->op_bytes; c->dst.val = (c->d & ByteOp) ? (s8) c->src.val : (s16) c->src.val; break; - case 0xc0 ... 0xc1: /* xadd */ - emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); - /* Write back the register source. */ - c->src.val = c->dst.orig_val; - write_register_operand(&c->src); - break; case 0xc3: /* movnti */ c->dst.bytes = c->op_bytes; c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val : @@ -3774,14 +3350,10 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) break; case 0xc7: /* Grp9 (cmpxchg8b) */ rc = emulate_grp9(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; - default: - goto cannot_emulate; } - - if (rc != X86EMUL_CONTINUE) - goto done; - goto writeback; cannot_emulate: diff --git a/trunk/arch/x86/kvm/i8254.c b/trunk/arch/x86/kvm/i8254.c index efad72385058..ddeb2314b522 100644 --- a/trunk/arch/x86/kvm/i8254.c +++ b/trunk/arch/x86/kvm/i8254.c @@ -5,7 +5,7 @@ * Copyright (c) 2006 Intel Corporation * Copyright (c) 2007 Keir Fraser, XenSource Inc * Copyright (c) 2008 Intel Corporation - * Copyright 2009 Red Hat, Inc. and/or its affiliates. + * Copyright 2009 Red Hat, Inc. and/or its affilates. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -232,6 +232,15 @@ static void pit_latch_status(struct kvm *kvm, int channel) } } +int pit_has_pending_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_pit *pit = vcpu->kvm->arch.vpit; + + if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack) + return atomic_read(&pit->pit_state.pit_timer.pending); + return 0; +} + static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) { struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state, diff --git a/trunk/arch/x86/kvm/i8259.c b/trunk/arch/x86/kvm/i8259.c index f628234fbeca..4b7b73ce2098 100644 --- a/trunk/arch/x86/kvm/i8259.c +++ b/trunk/arch/x86/kvm/i8259.c @@ -3,7 +3,7 @@ * * Copyright (c) 2003-2004 Fabrice Bellard * Copyright (c) 2007 Intel Corporation - * Copyright 2009 Red Hat, Inc. and/or its affiliates. + * Copyright 2009 Red Hat, Inc. and/or its affilates. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,7 @@ static void pic_irq_request(struct kvm *kvm, int level); static void pic_lock(struct kvm_pic *s) __acquires(&s->lock) { - spin_lock(&s->lock); + raw_spin_lock(&s->lock); } static void pic_unlock(struct kvm_pic *s) @@ -51,7 +51,7 @@ static void pic_unlock(struct kvm_pic *s) s->wakeup_needed = false; - spin_unlock(&s->lock); + raw_spin_unlock(&s->lock); if (wakeup) { kvm_for_each_vcpu(i, vcpu, s->kvm) { @@ -67,7 +67,6 @@ static void pic_unlock(struct kvm_pic *s) if (!found) return; - kvm_make_request(KVM_REQ_EVENT, found); kvm_vcpu_kick(found); } } @@ -309,17 +308,13 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) addr &= 1; if (addr == 0) { if (val & 0x10) { - s->init4 = val & 1; - s->last_irr = 0; - s->imr = 0; - s->priority_add = 0; - s->special_mask = 0; - s->read_reg_select = 0; - if (!s->init4) { - s->special_fully_nested_mode = 0; - s->auto_eoi = 0; - } + kvm_pic_reset(s); /* init */ + /* + * deassert a pending interrupt + */ + pic_irq_request(s->pics_state->kvm, 0); s->init_state = 1; + s->init4 = val & 1; if (val & 0x02) printk(KERN_ERR "single mode not supported"); if (val & 0x08) @@ -569,7 +564,7 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); if (!s) return NULL; - spin_lock_init(&s->lock); + raw_spin_lock_init(&s->lock); s->kvm = kvm; s->pics[0].elcr_mask = 0xf8; s->pics[1].elcr_mask = 0xde; diff --git a/trunk/arch/x86/kvm/irq.c b/trunk/arch/x86/kvm/irq.c index 7e06ba1618bd..2095a049835e 100644 --- a/trunk/arch/x86/kvm/irq.c +++ b/trunk/arch/x86/kvm/irq.c @@ -1,7 +1,7 @@ /* * irq.c: API for in kernel interrupt controller * Copyright (c) 2007, Intel Corporation. - * Copyright 2009 Red Hat, Inc. and/or its affiliates. + * Copyright 2009 Red Hat, Inc. and/or its affilates. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -33,7 +33,12 @@ */ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) { - return apic_has_pending_timer(vcpu); + int ret; + + ret = pit_has_pending_timer(vcpu); + ret |= apic_has_pending_timer(vcpu); + + return ret; } EXPORT_SYMBOL(kvm_cpu_has_pending_timer); diff --git a/trunk/arch/x86/kvm/irq.h b/trunk/arch/x86/kvm/irq.h index ba910d149410..63c314502993 100644 --- a/trunk/arch/x86/kvm/irq.h +++ b/trunk/arch/x86/kvm/irq.h @@ -60,7 +60,7 @@ struct kvm_kpic_state { }; struct kvm_pic { - spinlock_t lock; + raw_spinlock_t lock; bool wakeup_needed; unsigned pending_acks; struct kvm *kvm; diff --git a/trunk/arch/x86/kvm/kvm_cache_regs.h b/trunk/arch/x86/kvm/kvm_cache_regs.h index 975bb45329a1..6491ac8e755b 100644 --- a/trunk/arch/x86/kvm/kvm_cache_regs.h +++ b/trunk/arch/x86/kvm/kvm_cache_regs.h @@ -42,14 +42,7 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index) (unsigned long *)&vcpu->arch.regs_avail)) kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR); - return vcpu->arch.walk_mmu->pdptrs[index]; -} - -static inline u64 kvm_pdptr_read_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, int index) -{ - load_pdptrs(vcpu, mmu, mmu->get_cr3(vcpu)); - - return mmu->pdptrs[index]; + return vcpu->arch.pdptrs[index]; } static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask) diff --git a/trunk/arch/x86/kvm/lapic.c b/trunk/arch/x86/kvm/lapic.c index 413f8973a855..22b06f7660f4 100644 --- a/trunk/arch/x86/kvm/lapic.c +++ b/trunk/arch/x86/kvm/lapic.c @@ -5,7 +5,7 @@ * Copyright (C) 2006 Qumranet, Inc. * Copyright (C) 2007 Novell * Copyright (C) 2007 Intel - * Copyright 2009 Red Hat, Inc. and/or its affiliates. + * Copyright 2009 Red Hat, Inc. and/or its affilates. * * Authors: * Dor Laor @@ -259,10 +259,9 @@ static inline int apic_find_highest_isr(struct kvm_lapic *apic) static void apic_update_ppr(struct kvm_lapic *apic) { - u32 tpr, isrv, ppr, old_ppr; + u32 tpr, isrv, ppr; int isr; - old_ppr = apic_get_reg(apic, APIC_PROCPRI); tpr = apic_get_reg(apic, APIC_TASKPRI); isr = apic_find_highest_isr(apic); isrv = (isr != -1) ? isr : 0; @@ -275,10 +274,7 @@ static void apic_update_ppr(struct kvm_lapic *apic) apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", apic, ppr, isr, isrv); - if (old_ppr != ppr) { - apic_set_reg(apic, APIC_PROCPRI, ppr); - kvm_make_request(KVM_REQ_EVENT, apic->vcpu); - } + apic_set_reg(apic, APIC_PROCPRI, ppr); } static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) @@ -395,7 +391,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, break; } - kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); break; @@ -421,7 +416,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, "INIT on a runnable vcpu %d\n", vcpu->vcpu_id); vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; - kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); } else { apic_debug("Ignoring de-assert INIT to vcpu %d\n", @@ -436,7 +430,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, result = 1; vcpu->arch.sipi_vector = vector; vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; - kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); } break; @@ -482,7 +475,6 @@ static void apic_set_eoi(struct kvm_lapic *apic) trigger_mode = IOAPIC_EDGE_TRIG; if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); - kvm_make_request(KVM_REQ_EVENT, apic->vcpu); } static void apic_send_ipi(struct kvm_lapic *apic) @@ -1159,7 +1151,6 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) update_divide_count(apic); start_apic_timer(apic); apic->irr_pending = true; - kvm_make_request(KVM_REQ_EVENT, vcpu); } void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) diff --git a/trunk/arch/x86/kvm/mmu.c b/trunk/arch/x86/kvm/mmu.c index 908ea5464a51..311f6dad8951 100644 --- a/trunk/arch/x86/kvm/mmu.c +++ b/trunk/arch/x86/kvm/mmu.c @@ -7,7 +7,7 @@ * MMU support * * Copyright (C) 2006 Qumranet, Inc. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Authors: * Yaniv Kamay @@ -49,25 +49,15 @@ */ bool tdp_enabled = false; -enum { - AUDIT_PRE_PAGE_FAULT, - AUDIT_POST_PAGE_FAULT, - AUDIT_PRE_PTE_WRITE, - AUDIT_POST_PTE_WRITE, - AUDIT_PRE_SYNC, - AUDIT_POST_SYNC -}; +#undef MMU_DEBUG -char *audit_point_name[] = { - "pre page fault", - "post page fault", - "pre pte write", - "post pte write", - "pre sync", - "post sync" -}; +#undef AUDIT -#undef MMU_DEBUG +#ifdef AUDIT +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); +#else +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} +#endif #ifdef MMU_DEBUG @@ -81,7 +71,7 @@ char *audit_point_name[] = { #endif -#ifdef MMU_DEBUG +#if defined(MMU_DEBUG) || defined(AUDIT) static int dbg = 0; module_param(dbg, bool, 0644); #endif @@ -99,8 +89,6 @@ module_param(oos_shadow, bool, 0644); } #endif -#define PTE_PREFETCH_NUM 8 - #define PT_FIRST_AVAIL_BITS_SHIFT 9 #define PT64_SECOND_AVAIL_BITS_SHIFT 52 @@ -190,7 +178,6 @@ typedef void (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp, u64 *spte); static struct kmem_cache *pte_chain_cache; static struct kmem_cache *rmap_desc_cache; static struct kmem_cache *mmu_page_header_cache; -static struct percpu_counter kvm_total_used_mmu_pages; static u64 __read_mostly shadow_trap_nonpresent_pte; static u64 __read_mostly shadow_notrap_nonpresent_pte; @@ -312,50 +299,18 @@ static u64 __xchg_spte(u64 *sptep, u64 new_spte) #endif } -static bool spte_has_volatile_bits(u64 spte) -{ - if (!shadow_accessed_mask) - return false; - - if (!is_shadow_present_pte(spte)) - return false; - - if ((spte & shadow_accessed_mask) && - (!is_writable_pte(spte) || (spte & shadow_dirty_mask))) - return false; - - return true; -} - -static bool spte_is_bit_cleared(u64 old_spte, u64 new_spte, u64 bit_mask) -{ - return (old_spte & bit_mask) && !(new_spte & bit_mask); -} - static void update_spte(u64 *sptep, u64 new_spte) { - u64 mask, old_spte = *sptep; - - WARN_ON(!is_rmap_spte(new_spte)); - - new_spte |= old_spte & shadow_dirty_mask; - - mask = shadow_accessed_mask; - if (is_writable_pte(old_spte)) - mask |= shadow_dirty_mask; + u64 old_spte; - if (!spte_has_volatile_bits(old_spte) || (new_spte & mask) == mask) + if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) || + !is_rmap_spte(*sptep)) __set_spte(sptep, new_spte); - else + else { old_spte = __xchg_spte(sptep, new_spte); - - if (!shadow_accessed_mask) - return; - - if (spte_is_bit_cleared(old_spte, new_spte, shadow_accessed_mask)) - kvm_set_pfn_accessed(spte_to_pfn(old_spte)); - if (spte_is_bit_cleared(old_spte, new_spte, shadow_dirty_mask)) - kvm_set_pfn_dirty(spte_to_pfn(old_spte)); + if (old_spte & shadow_accessed_mask) + mark_page_accessed(pfn_to_page(spte_to_pfn(old_spte))); + } } static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, @@ -412,7 +367,7 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) if (r) goto out; r = mmu_topup_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, - rmap_desc_cache, 4 + PTE_PREFETCH_NUM); + rmap_desc_cache, 4); if (r) goto out; r = mmu_topup_memory_cache_page(&vcpu->arch.mmu_page_cache, 8); @@ -636,7 +591,6 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) desc->sptes[0] = (u64 *)*rmapp; desc->sptes[1] = spte; *rmapp = (unsigned long)desc | 1; - ++count; } else { rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); @@ -649,7 +603,7 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) desc = desc->more; } for (i = 0; desc->sptes[i]; ++i) - ++count; + ; desc->sptes[i] = spte; } return count; @@ -691,17 +645,18 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt); rmapp = gfn_to_rmap(kvm, gfn, sp->role.level); if (!*rmapp) { - printk(KERN_ERR "rmap_remove: %p 0->BUG\n", spte); + printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); BUG(); } else if (!(*rmapp & 1)) { - rmap_printk("rmap_remove: %p 1->0\n", spte); + rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte); if ((u64 *)*rmapp != spte) { - printk(KERN_ERR "rmap_remove: %p 1->BUG\n", spte); + printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n", + spte, *spte); BUG(); } *rmapp = 0; } else { - rmap_printk("rmap_remove: %p many->many\n", spte); + rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte); desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); prev_desc = NULL; while (desc) { @@ -715,7 +670,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) prev_desc = desc; desc = desc->more; } - pr_err("rmap_remove: %p many->many\n", spte); + pr_err("rmap_remove: %p %llx many->many\n", spte, *spte); BUG(); } } @@ -725,18 +680,18 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte) pfn_t pfn; u64 old_spte = *sptep; - if (!spte_has_volatile_bits(old_spte)) + if (!shadow_accessed_mask || !is_shadow_present_pte(old_spte) || + old_spte & shadow_accessed_mask) { __set_spte(sptep, new_spte); - else + } else old_spte = __xchg_spte(sptep, new_spte); if (!is_rmap_spte(old_spte)) return; - pfn = spte_to_pfn(old_spte); if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) kvm_set_pfn_accessed(pfn); - if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) + if (is_writable_pte(old_spte)) kvm_set_pfn_dirty(pfn); } @@ -791,6 +746,13 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) } spte = rmap_next(kvm, rmapp, spte); } + if (write_protected) { + pfn_t pfn; + + spte = rmap_next(kvm, rmapp, NULL); + pfn = spte_to_pfn(*spte); + kvm_set_pfn_dirty(pfn); + } /* check for huge page mappings */ for (i = PT_DIRECTORY_LEVEL; @@ -985,18 +947,6 @@ static int is_empty_shadow_page(u64 *spt) } #endif -/* - * This value is the sum of all of the kvm instances's - * kvm->arch.n_used_mmu_pages values. We need a global, - * aggregate version in order to make the slab shrinker - * faster - */ -static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, int nr) -{ - kvm->arch.n_used_mmu_pages += nr; - percpu_counter_add(&kvm_total_used_mmu_pages, nr); -} - static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp) { ASSERT(is_empty_shadow_page(sp->spt)); @@ -1006,7 +956,7 @@ static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp) if (!sp->role.direct) __free_page(virt_to_page(sp->gfns)); kmem_cache_free(mmu_page_header_cache, sp); - kvm_mod_used_mmu_pages(kvm, -1); + ++kvm->arch.n_free_mmu_pages; } static unsigned kvm_page_table_hashfn(gfn_t gfn) @@ -1029,7 +979,7 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); sp->multimapped = 0; sp->parent_pte = parent_pte; - kvm_mod_used_mmu_pages(vcpu->kvm, +1); + --vcpu->kvm->arch.n_free_mmu_pages; return sp; } @@ -1453,8 +1403,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, if (role.direct) role.cr4_pae = 0; role.access = access; - if (!vcpu->arch.mmu.direct_map - && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) { + if (!tdp_enabled && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) { quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; role.quadrant = quadrant; @@ -1509,12 +1458,6 @@ static void shadow_walk_init(struct kvm_shadow_walk_iterator *iterator, iterator->addr = addr; iterator->shadow_addr = vcpu->arch.mmu.root_hpa; iterator->level = vcpu->arch.mmu.shadow_root_level; - - if (iterator->level == PT64_ROOT_LEVEL && - vcpu->arch.mmu.root_level < PT64_ROOT_LEVEL && - !vcpu->arch.mmu.direct_map) - --iterator->level; - if (iterator->level == PT32E_ROOT_LEVEL) { iterator->shadow_addr = vcpu->arch.mmu.pae_root[(addr >> 30) & 3]; @@ -1722,31 +1665,41 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, /* * Changing the number of mmu pages allocated to the vm - * Note: if goal_nr_mmu_pages is too small, you will get dead lock + * Note: if kvm_nr_mmu_pages is too small, you will get dead lock */ -void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages) +void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) { + int used_pages; LIST_HEAD(invalid_list); + + used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages; + used_pages = max(0, used_pages); + /* * If we set the number of mmu pages to be smaller be than the * number of actived pages , we must to free some mmu pages before we * change the value */ - if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) { - while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages && + if (used_pages > kvm_nr_mmu_pages) { + while (used_pages > kvm_nr_mmu_pages && !list_empty(&kvm->arch.active_mmu_pages)) { struct kvm_mmu_page *page; page = container_of(kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_prepare_zap_page(kvm, page, &invalid_list); - kvm_mmu_commit_zap_page(kvm, &invalid_list); + used_pages -= kvm_mmu_prepare_zap_page(kvm, page, + &invalid_list); } - goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages; + kvm_mmu_commit_zap_page(kvm, &invalid_list); + kvm_nr_mmu_pages = used_pages; + kvm->arch.n_free_mmu_pages = 0; } + else + kvm->arch.n_free_mmu_pages += kvm_nr_mmu_pages + - kvm->arch.n_alloc_mmu_pages; - kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages; + kvm->arch.n_alloc_mmu_pages = kvm_nr_mmu_pages; } static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn) @@ -1756,11 +1709,11 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn) LIST_HEAD(invalid_list); int r; - pgprintk("%s: looking for gfn %llx\n", __func__, gfn); + pgprintk("%s: looking for gfn %lx\n", __func__, gfn); r = 0; for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) { - pgprintk("%s: gfn %llx role %x\n", __func__, gfn, + pgprintk("%s: gfn %lx role %x\n", __func__, gfn, sp->role.word); r = 1; kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); @@ -1776,7 +1729,7 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) LIST_HEAD(invalid_list); for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) { - pgprintk("%s: zap %llx %x\n", + pgprintk("%s: zap %lx %x\n", __func__, gfn, sp->role.word); kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); } @@ -1972,7 +1925,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, * whether the guest actually used the pte (in order to detect * demand paging). */ - spte = shadow_base_present_pte; + spte = shadow_base_present_pte | shadow_dirty_mask; if (!speculative) spte |= shadow_accessed_mask; if (!dirty) @@ -1995,8 +1948,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, spte |= (u64)pfn << PAGE_SHIFT; if ((pte_access & ACC_WRITE_MASK) - || (!vcpu->arch.mmu.direct_map && write_fault - && !is_write_protection(vcpu) && !user_fault)) { + || (!tdp_enabled && write_fault && !is_write_protection(vcpu) + && !user_fault)) { if (level > PT_PAGE_TABLE_LEVEL && has_wrprotected_page(vcpu->kvm, gfn, level)) { @@ -2007,8 +1960,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, spte |= PT_WRITABLE_MASK; - if (!vcpu->arch.mmu.direct_map - && !(pte_access & ACC_WRITE_MASK)) + if (!tdp_enabled && !(pte_access & ACC_WRITE_MASK)) spte &= ~PT_USER_MASK; /* @@ -2021,7 +1973,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, goto set_pte; if (mmu_need_write_protect(vcpu, gfn, can_unsync)) { - pgprintk("%s: found shadow page for %llx, marking ro\n", + pgprintk("%s: found shadow page for %lx, marking ro\n", __func__, gfn); ret = 1; pte_access &= ~ACC_WRITE_MASK; @@ -2034,6 +1986,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, mark_page_dirty(vcpu->kvm, gfn); set_pte: + if (is_writable_pte(*sptep) && !is_writable_pte(spte)) + kvm_set_pfn_dirty(pfn); update_spte(sptep, spte); done: return ret; @@ -2050,7 +2004,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, int rmap_count; pgprintk("%s: spte %llx access %x write_fault %d" - " user_fault %d gfn %llx\n", + " user_fault %d gfn %lx\n", __func__, *sptep, pt_access, write_fault, user_fault, gfn); @@ -2069,7 +2023,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, __set_spte(sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); } else if (pfn != spte_to_pfn(*sptep)) { - pgprintk("hfn old %llx new %llx\n", + pgprintk("hfn old %lx new %lx\n", spte_to_pfn(*sptep), pfn); drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte); kvm_flush_remote_tlbs(vcpu->kvm); @@ -2086,7 +2040,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, } pgprintk("%s: setting spte %llx\n", __func__, *sptep); - pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n", + pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n", is_large_pte(*sptep)? "2MB" : "4kB", *sptep & PT_PRESENT_MASK ?"RW":"R", gfn, *sptep, sptep); @@ -2110,105 +2064,6 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) { } -static struct kvm_memory_slot * -pte_prefetch_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn, bool no_dirty_log) -{ - struct kvm_memory_slot *slot; - - slot = gfn_to_memslot(vcpu->kvm, gfn); - if (!slot || slot->flags & KVM_MEMSLOT_INVALID || - (no_dirty_log && slot->dirty_bitmap)) - slot = NULL; - - return slot; -} - -static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, - bool no_dirty_log) -{ - struct kvm_memory_slot *slot; - unsigned long hva; - - slot = pte_prefetch_gfn_to_memslot(vcpu, gfn, no_dirty_log); - if (!slot) { - get_page(bad_page); - return page_to_pfn(bad_page); - } - - hva = gfn_to_hva_memslot(slot, gfn); - - return hva_to_pfn_atomic(vcpu->kvm, hva); -} - -static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp, - u64 *start, u64 *end) -{ - struct page *pages[PTE_PREFETCH_NUM]; - unsigned access = sp->role.access; - int i, ret; - gfn_t gfn; - - gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt); - if (!pte_prefetch_gfn_to_memslot(vcpu, gfn, access & ACC_WRITE_MASK)) - return -1; - - ret = gfn_to_page_many_atomic(vcpu->kvm, gfn, pages, end - start); - if (ret <= 0) - return -1; - - for (i = 0; i < ret; i++, gfn++, start++) - mmu_set_spte(vcpu, start, ACC_ALL, - access, 0, 0, 1, NULL, - sp->role.level, gfn, - page_to_pfn(pages[i]), true, true); - - return 0; -} - -static void __direct_pte_prefetch(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp, u64 *sptep) -{ - u64 *spte, *start = NULL; - int i; - - WARN_ON(!sp->role.direct); - - i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1); - spte = sp->spt + i; - - for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) { - if (*spte != shadow_trap_nonpresent_pte || spte == sptep) { - if (!start) - continue; - if (direct_pte_prefetch_many(vcpu, sp, start, spte) < 0) - break; - start = NULL; - } else if (!start) - start = spte; - } -} - -static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) -{ - struct kvm_mmu_page *sp; - - /* - * Since it's no accessed bit on EPT, it's no way to - * distinguish between actually accessed translations - * and prefetched, so disable pte prefetch if EPT is - * enabled. - */ - if (!shadow_accessed_mask) - return; - - sp = page_header(__pa(sptep)); - if (sp->role.level > PT_PAGE_TABLE_LEVEL) - return; - - __direct_pte_prefetch(vcpu, sp, sptep); -} - static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, int level, gfn_t gfn, pfn_t pfn) { @@ -2222,7 +2077,6 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, 0, write, 1, &pt_write, level, gfn, pfn, false, true); - direct_pte_prefetch(vcpu, iterator.sptep); ++vcpu->stat.pf_fixed; break; } @@ -2244,31 +2098,28 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, __set_spte(iterator.sptep, __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK - | shadow_user_mask | shadow_x_mask - | shadow_accessed_mask); + | shadow_user_mask | shadow_x_mask); } } return pt_write; } -static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk) +static void kvm_send_hwpoison_signal(struct kvm *kvm, gfn_t gfn) { - siginfo_t info; - - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_MCEERR_AR; - info.si_addr = (void __user *)address; - info.si_addr_lsb = PAGE_SHIFT; + char buf[1]; + void __user *hva; + int r; - send_sig_info(SIGBUS, &info, tsk); + /* Touch the page, so send SIGBUS */ + hva = (void __user *)gfn_to_hva(kvm, gfn); + r = copy_from_user(buf, hva, 1); } static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn) { kvm_release_pfn_clean(pfn); if (is_hwpoison_pfn(pfn)) { - kvm_send_hwpoison_signal(gfn_to_hva(kvm, gfn), current); + kvm_send_hwpoison_signal(kvm, gfn); return 0; } else if (is_fault_pfn(pfn)) return -EFAULT; @@ -2328,9 +2179,7 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) return; spin_lock(&vcpu->kvm->mmu_lock); - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL && - (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL || - vcpu->arch.mmu.direct_map)) { + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { hpa_t root = vcpu->arch.mmu.root_hpa; sp = page_header(root); @@ -2373,158 +2222,80 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) return ret; } -static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu_page *sp; - unsigned i; - - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { - spin_lock(&vcpu->kvm->mmu_lock); - kvm_mmu_free_some_pages(vcpu); - sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL, - 1, ACC_ALL, NULL); - ++sp->root_count; - spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.root_hpa = __pa(sp->spt); - } else if (vcpu->arch.mmu.shadow_root_level == PT32E_ROOT_LEVEL) { - for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; - - ASSERT(!VALID_PAGE(root)); - spin_lock(&vcpu->kvm->mmu_lock); - kvm_mmu_free_some_pages(vcpu); - sp = kvm_mmu_get_page(vcpu, i << 30, i << 30, - PT32_ROOT_LEVEL, 1, ACC_ALL, - NULL); - root = __pa(sp->spt); - ++sp->root_count; - spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; - } - vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); - } else - BUG(); - - return 0; -} - -static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) +static int mmu_alloc_roots(struct kvm_vcpu *vcpu) { - struct kvm_mmu_page *sp; - u64 pdptr, pm_mask; - gfn_t root_gfn; int i; + gfn_t root_gfn; + struct kvm_mmu_page *sp; + int direct = 0; + u64 pdptr; - root_gfn = vcpu->arch.mmu.get_cr3(vcpu) >> PAGE_SHIFT; - - if (mmu_check_root(vcpu, root_gfn)) - return 1; + root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT; - /* - * Do we shadow a long mode page table? If so we need to - * write-protect the guests page table root. - */ - if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) { + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { hpa_t root = vcpu->arch.mmu.root_hpa; ASSERT(!VALID_PAGE(root)); - + if (mmu_check_root(vcpu, root_gfn)) + return 1; + if (tdp_enabled) { + direct = 1; + root_gfn = 0; + } spin_lock(&vcpu->kvm->mmu_lock); kvm_mmu_free_some_pages(vcpu); - sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL, - 0, ACC_ALL, NULL); + sp = kvm_mmu_get_page(vcpu, root_gfn, 0, + PT64_ROOT_LEVEL, direct, + ACC_ALL, NULL); root = __pa(sp->spt); ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); vcpu->arch.mmu.root_hpa = root; return 0; } - - /* - * We shadow a 32 bit page table. This may be a legacy 2-level - * or a PAE 3-level page table. In either case we need to be aware that - * the shadow page table may be a PAE or a long mode page table. - */ - pm_mask = PT_PRESENT_MASK; - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) - pm_mask |= PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK; - + direct = !is_paging(vcpu); for (i = 0; i < 4; ++i) { hpa_t root = vcpu->arch.mmu.pae_root[i]; ASSERT(!VALID_PAGE(root)); if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) { - pdptr = kvm_pdptr_read_mmu(vcpu, &vcpu->arch.mmu, i); + pdptr = kvm_pdptr_read(vcpu, i); if (!is_present_gpte(pdptr)) { vcpu->arch.mmu.pae_root[i] = 0; continue; } root_gfn = pdptr >> PAGE_SHIFT; - if (mmu_check_root(vcpu, root_gfn)) - return 1; + } else if (vcpu->arch.mmu.root_level == 0) + root_gfn = 0; + if (mmu_check_root(vcpu, root_gfn)) + return 1; + if (tdp_enabled) { + direct = 1; + root_gfn = i << 30; } spin_lock(&vcpu->kvm->mmu_lock); kvm_mmu_free_some_pages(vcpu); sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, - PT32_ROOT_LEVEL, 0, + PT32_ROOT_LEVEL, direct, ACC_ALL, NULL); root = __pa(sp->spt); ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.pae_root[i] = root | pm_mask; + vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; } vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); - - /* - * If we shadow a 32 bit page table with a long mode page - * table we enter this path. - */ - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { - if (vcpu->arch.mmu.lm_root == NULL) { - /* - * The additional page necessary for this is only - * allocated on demand. - */ - - u64 *lm_root; - - lm_root = (void*)get_zeroed_page(GFP_KERNEL); - if (lm_root == NULL) - return 1; - - lm_root[0] = __pa(vcpu->arch.mmu.pae_root) | pm_mask; - - vcpu->arch.mmu.lm_root = lm_root; - } - - vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.lm_root); - } - return 0; } -static int mmu_alloc_roots(struct kvm_vcpu *vcpu) -{ - if (vcpu->arch.mmu.direct_map) - return mmu_alloc_direct_roots(vcpu); - else - return mmu_alloc_shadow_roots(vcpu); -} - static void mmu_sync_roots(struct kvm_vcpu *vcpu) { int i; struct kvm_mmu_page *sp; - if (vcpu->arch.mmu.direct_map) - return; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) return; - - trace_kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC); - if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) { + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { hpa_t root = vcpu->arch.mmu.root_hpa; sp = page_header(root); mmu_sync_children(vcpu, sp); @@ -2539,7 +2310,6 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu) mmu_sync_children(vcpu, sp); } } - trace_kvm_mmu_audit(vcpu, AUDIT_POST_SYNC); } void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) @@ -2557,14 +2327,6 @@ static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr, return vaddr; } -static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr, - u32 access, u32 *error) -{ - if (error) - *error = 0; - return vcpu->arch.nested_mmu.translate_gpa(vcpu, vaddr, access); -} - static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code) { @@ -2631,9 +2393,10 @@ static void nonpaging_free(struct kvm_vcpu *vcpu) mmu_free_roots(vcpu); } -static int nonpaging_init_context(struct kvm_vcpu *vcpu, - struct kvm_mmu *context) +static int nonpaging_init_context(struct kvm_vcpu *vcpu) { + struct kvm_mmu *context = &vcpu->arch.mmu; + context->new_cr3 = nonpaging_new_cr3; context->page_fault = nonpaging_page_fault; context->gva_to_gpa = nonpaging_gva_to_gpa; @@ -2644,8 +2407,6 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu, context->root_level = 0; context->shadow_root_level = PT32E_ROOT_LEVEL; context->root_hpa = INVALID_PAGE; - context->direct_map = true; - context->nx = false; return 0; } @@ -2661,14 +2422,11 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu) mmu_free_roots(vcpu); } -static unsigned long get_cr3(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.cr3; -} - -static void inject_page_fault(struct kvm_vcpu *vcpu) +static void inject_page_fault(struct kvm_vcpu *vcpu, + u64 addr, + u32 err_code) { - vcpu->arch.mmu.inject_page_fault(vcpu); + kvm_inject_page_fault(vcpu, addr, err_code); } static void paging_free(struct kvm_vcpu *vcpu) @@ -2676,12 +2434,12 @@ static void paging_free(struct kvm_vcpu *vcpu) nonpaging_free(vcpu); } -static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level) +static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level) { int bit7; bit7 = (gpte >> 7) & 1; - return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0; + return (gpte & vcpu->arch.mmu.rsvd_bits_mask[bit7][level-1]) != 0; } #define PTTYPE 64 @@ -2692,14 +2450,13 @@ static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level) #include "paging_tmpl.h" #undef PTTYPE -static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, - struct kvm_mmu *context, - int level) +static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level) { + struct kvm_mmu *context = &vcpu->arch.mmu; int maxphyaddr = cpuid_maxphyaddr(vcpu); u64 exb_bit_rsvd = 0; - if (!context->nx) + if (!is_nx(vcpu)) exb_bit_rsvd = rsvd_bits(63, 63); switch (level) { case PT32_ROOT_LEVEL: @@ -2754,13 +2511,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, } } -static int paging64_init_context_common(struct kvm_vcpu *vcpu, - struct kvm_mmu *context, - int level) +static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) { - context->nx = is_nx(vcpu); - - reset_rsvds_bits_mask(vcpu, context, level); + struct kvm_mmu *context = &vcpu->arch.mmu; ASSERT(is_pae(vcpu)); context->new_cr3 = paging_new_cr3; @@ -2773,23 +2526,20 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, context->root_level = level; context->shadow_root_level = level; context->root_hpa = INVALID_PAGE; - context->direct_map = false; return 0; } -static int paging64_init_context(struct kvm_vcpu *vcpu, - struct kvm_mmu *context) +static int paging64_init_context(struct kvm_vcpu *vcpu) { - return paging64_init_context_common(vcpu, context, PT64_ROOT_LEVEL); + reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL); + return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL); } -static int paging32_init_context(struct kvm_vcpu *vcpu, - struct kvm_mmu *context) +static int paging32_init_context(struct kvm_vcpu *vcpu) { - context->nx = false; - - reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL); + struct kvm_mmu *context = &vcpu->arch.mmu; + reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL); context->new_cr3 = paging_new_cr3; context->page_fault = paging32_page_fault; context->gva_to_gpa = paging32_gva_to_gpa; @@ -2800,19 +2550,18 @@ static int paging32_init_context(struct kvm_vcpu *vcpu, context->root_level = PT32_ROOT_LEVEL; context->shadow_root_level = PT32E_ROOT_LEVEL; context->root_hpa = INVALID_PAGE; - context->direct_map = false; return 0; } -static int paging32E_init_context(struct kvm_vcpu *vcpu, - struct kvm_mmu *context) +static int paging32E_init_context(struct kvm_vcpu *vcpu) { - return paging64_init_context_common(vcpu, context, PT32E_ROOT_LEVEL); + reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL); + return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); } static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) { - struct kvm_mmu *context = vcpu->arch.walk_mmu; + struct kvm_mmu *context = &vcpu->arch.mmu; context->new_cr3 = nonpaging_new_cr3; context->page_fault = tdp_page_fault; @@ -2822,29 +2571,20 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) context->invlpg = nonpaging_invlpg; context->shadow_root_level = kvm_x86_ops->get_tdp_level(); context->root_hpa = INVALID_PAGE; - context->direct_map = true; - context->set_cr3 = kvm_x86_ops->set_tdp_cr3; - context->get_cr3 = get_cr3; - context->inject_page_fault = kvm_inject_page_fault; - context->nx = is_nx(vcpu); if (!is_paging(vcpu)) { - context->nx = false; context->gva_to_gpa = nonpaging_gva_to_gpa; context->root_level = 0; } else if (is_long_mode(vcpu)) { - context->nx = is_nx(vcpu); - reset_rsvds_bits_mask(vcpu, context, PT64_ROOT_LEVEL); + reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL); context->gva_to_gpa = paging64_gva_to_gpa; context->root_level = PT64_ROOT_LEVEL; } else if (is_pae(vcpu)) { - context->nx = is_nx(vcpu); - reset_rsvds_bits_mask(vcpu, context, PT32E_ROOT_LEVEL); + reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL); context->gva_to_gpa = paging64_gva_to_gpa; context->root_level = PT32E_ROOT_LEVEL; } else { - context->nx = false; - reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL); + reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL); context->gva_to_gpa = paging32_gva_to_gpa; context->root_level = PT32_ROOT_LEVEL; } @@ -2852,83 +2592,33 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) return 0; } -int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context) +static int init_kvm_softmmu(struct kvm_vcpu *vcpu) { int r; + ASSERT(vcpu); ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); if (!is_paging(vcpu)) - r = nonpaging_init_context(vcpu, context); + r = nonpaging_init_context(vcpu); else if (is_long_mode(vcpu)) - r = paging64_init_context(vcpu, context); + r = paging64_init_context(vcpu); else if (is_pae(vcpu)) - r = paging32E_init_context(vcpu, context); + r = paging32E_init_context(vcpu); else - r = paging32_init_context(vcpu, context); + r = paging32_init_context(vcpu); vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu); - vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu); + vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu); return r; } -EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); - -static int init_kvm_softmmu(struct kvm_vcpu *vcpu) -{ - int r = kvm_init_shadow_mmu(vcpu, vcpu->arch.walk_mmu); - - vcpu->arch.walk_mmu->set_cr3 = kvm_x86_ops->set_cr3; - vcpu->arch.walk_mmu->get_cr3 = get_cr3; - vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; - - return r; -} - -static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu *g_context = &vcpu->arch.nested_mmu; - - g_context->get_cr3 = get_cr3; - g_context->inject_page_fault = kvm_inject_page_fault; - - /* - * Note that arch.mmu.gva_to_gpa translates l2_gva to l1_gpa. The - * translation of l2_gpa to l1_gpa addresses is done using the - * arch.nested_mmu.gva_to_gpa function. Basically the gva_to_gpa - * functions between mmu and nested_mmu are swapped. - */ - if (!is_paging(vcpu)) { - g_context->nx = false; - g_context->root_level = 0; - g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested; - } else if (is_long_mode(vcpu)) { - g_context->nx = is_nx(vcpu); - reset_rsvds_bits_mask(vcpu, g_context, PT64_ROOT_LEVEL); - g_context->root_level = PT64_ROOT_LEVEL; - g_context->gva_to_gpa = paging64_gva_to_gpa_nested; - } else if (is_pae(vcpu)) { - g_context->nx = is_nx(vcpu); - reset_rsvds_bits_mask(vcpu, g_context, PT32E_ROOT_LEVEL); - g_context->root_level = PT32E_ROOT_LEVEL; - g_context->gva_to_gpa = paging64_gva_to_gpa_nested; - } else { - g_context->nx = false; - reset_rsvds_bits_mask(vcpu, g_context, PT32_ROOT_LEVEL); - g_context->root_level = PT32_ROOT_LEVEL; - g_context->gva_to_gpa = paging32_gva_to_gpa_nested; - } - - return 0; -} static int init_kvm_mmu(struct kvm_vcpu *vcpu) { vcpu->arch.update_pte.pfn = bad_pfn; - if (mmu_is_nested(vcpu)) - return init_kvm_nested_mmu(vcpu); - else if (tdp_enabled) + if (tdp_enabled) return init_kvm_tdp_mmu(vcpu); else return init_kvm_softmmu(vcpu); @@ -2963,7 +2653,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) if (r) goto out; /* set_cr3() should ensure TLB has been flushed */ - vcpu->arch.mmu.set_cr3(vcpu, vcpu->arch.mmu.root_hpa); + kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa); out: return r; } @@ -2973,7 +2663,6 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu) { mmu_free_roots(vcpu); } -EXPORT_SYMBOL_GPL(kvm_mmu_unload); static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, @@ -3006,7 +2695,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, return; } - if (is_rsvd_bits_set(&vcpu->arch.mmu, *(u64 *)new, PT_PAGE_TABLE_LEVEL)) + if (is_rsvd_bits_set(vcpu, *(u64 *)new, PT_PAGE_TABLE_LEVEL)) return; ++vcpu->kvm->stat.mmu_pte_updated; @@ -3148,7 +2837,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, kvm_mmu_access_page(vcpu, gfn); kvm_mmu_free_some_pages(vcpu); ++vcpu->kvm->stat.mmu_pte_write; - trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE); + kvm_mmu_audit(vcpu, "pre pte write"); if (guest_initiated) { if (gfn == vcpu->arch.last_pt_write_gfn && !last_updated_pte_accessed(vcpu)) { @@ -3221,7 +2910,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, } mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush); kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); - trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE); + kvm_mmu_audit(vcpu, "post pte write"); spin_unlock(&vcpu->kvm->mmu_lock); if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); @@ -3234,7 +2923,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) gpa_t gpa; int r; - if (vcpu->arch.mmu.direct_map) + if (tdp_enabled) return 0; gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL); @@ -3248,18 +2937,21 @@ EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt); void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) { + int free_pages; LIST_HEAD(invalid_list); - while (kvm_mmu_available_pages(vcpu->kvm) < KVM_REFILL_PAGES && + free_pages = vcpu->kvm->arch.n_free_mmu_pages; + while (free_pages < KVM_REFILL_PAGES && !list_empty(&vcpu->kvm->arch.active_mmu_pages)) { struct kvm_mmu_page *sp; sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list); - kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); + free_pages += kvm_mmu_prepare_zap_page(vcpu->kvm, sp, + &invalid_list); ++vcpu->kvm->stat.mmu_recycled; } + kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); } int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) @@ -3321,8 +3013,6 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp); static void free_mmu_pages(struct kvm_vcpu *vcpu) { free_page((unsigned long)vcpu->arch.mmu.pae_root); - if (vcpu->arch.mmu.lm_root != NULL) - free_page((unsigned long)vcpu->arch.mmu.lm_root); } static int alloc_mmu_pages(struct kvm_vcpu *vcpu) @@ -3364,6 +3054,15 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu) return init_kvm_mmu(vcpu); } +void kvm_mmu_destroy(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + + destroy_kvm_mmu(vcpu); + free_mmu_pages(vcpu); + mmu_free_memory_caches(vcpu); +} + void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) { struct kvm_mmu_page *sp; @@ -3413,22 +3112,23 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) { struct kvm *kvm; struct kvm *kvm_freed = NULL; - - if (nr_to_scan == 0) - goto out; + int cache_count = 0; spin_lock(&kvm_lock); list_for_each_entry(kvm, &vm_list, vm_list) { - int idx, freed_pages; + int npages, idx, freed_pages; LIST_HEAD(invalid_list); idx = srcu_read_lock(&kvm->srcu); spin_lock(&kvm->mmu_lock); - if (!kvm_freed && nr_to_scan > 0 && - kvm->arch.n_used_mmu_pages > 0) { + npages = kvm->arch.n_alloc_mmu_pages - + kvm->arch.n_free_mmu_pages; + cache_count += npages; + if (!kvm_freed && nr_to_scan > 0 && npages > 0) { freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm, &invalid_list); + cache_count -= freed_pages; kvm_freed = kvm; } nr_to_scan--; @@ -3442,8 +3142,7 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) spin_unlock(&kvm_lock); -out: - return percpu_counter_read_positive(&kvm_total_used_mmu_pages); + return cache_count; } static struct shrinker mmu_shrinker = { @@ -3464,7 +3163,6 @@ static void mmu_destroy_caches(void) void kvm_mmu_module_exit(void) { mmu_destroy_caches(); - percpu_counter_destroy(&kvm_total_used_mmu_pages); unregister_shrinker(&mmu_shrinker); } @@ -3487,9 +3185,6 @@ int kvm_mmu_module_init(void) if (!mmu_page_header_cache) goto nomem; - if (percpu_counter_init(&kvm_total_used_mmu_pages, 0)) - goto nomem; - register_shrinker(&mmu_shrinker); return 0; @@ -3660,18 +3355,271 @@ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]) } EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); -#ifdef CONFIG_KVM_MMU_AUDIT -#include "mmu_audit.c" -#else -static void mmu_audit_disable(void) { } +#ifdef AUDIT + +static const char *audit_msg; + +static gva_t canonicalize(gva_t gva) +{ +#ifdef CONFIG_X86_64 + gva = (long long)(gva << 16) >> 16; #endif + return gva; +} -void kvm_mmu_destroy(struct kvm_vcpu *vcpu) + +typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); + +static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, + inspect_spte_fn fn) { - ASSERT(vcpu); + int i; - destroy_kvm_mmu(vcpu); - free_mmu_pages(vcpu); - mmu_free_memory_caches(vcpu); - mmu_audit_disable(); + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + u64 ent = sp->spt[i]; + + if (is_shadow_present_pte(ent)) { + if (!is_last_spte(ent, sp->role.level)) { + struct kvm_mmu_page *child; + child = page_header(ent & PT64_BASE_ADDR_MASK); + __mmu_spte_walk(kvm, child, fn); + } else + fn(kvm, &sp->spt[i]); + } + } +} + +static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) +{ + int i; + struct kvm_mmu_page *sp; + + if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + return; + if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { + hpa_t root = vcpu->arch.mmu.root_hpa; + sp = page_header(root); + __mmu_spte_walk(vcpu->kvm, sp, fn); + return; + } + for (i = 0; i < 4; ++i) { + hpa_t root = vcpu->arch.mmu.pae_root[i]; + + if (root && VALID_PAGE(root)) { + root &= PT64_BASE_ADDR_MASK; + sp = page_header(root); + __mmu_spte_walk(vcpu->kvm, sp, fn); + } + } + return; } + +static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, + gva_t va, int level) +{ + u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK); + int i; + gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { + u64 ent = pt[i]; + + if (ent == shadow_trap_nonpresent_pte) + continue; + + va = canonicalize(va); + if (is_shadow_present_pte(ent) && !is_last_spte(ent, level)) + audit_mappings_page(vcpu, ent, va, level - 1); + else { + gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL); + gfn_t gfn = gpa >> PAGE_SHIFT; + pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn); + hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT; + + if (is_error_pfn(pfn)) { + kvm_release_pfn_clean(pfn); + continue; + } + + if (is_shadow_present_pte(ent) + && (ent & PT64_BASE_ADDR_MASK) != hpa) + printk(KERN_ERR "xx audit error: (%s) levels %d" + " gva %lx gpa %llx hpa %llx ent %llx %d\n", + audit_msg, vcpu->arch.mmu.root_level, + va, gpa, hpa, ent, + is_shadow_present_pte(ent)); + else if (ent == shadow_notrap_nonpresent_pte + && !is_error_hpa(hpa)) + printk(KERN_ERR "audit: (%s) notrap shadow," + " valid guest gva %lx\n", audit_msg, va); + kvm_release_pfn_clean(pfn); + + } + } +} + +static void audit_mappings(struct kvm_vcpu *vcpu) +{ + unsigned i; + + if (vcpu->arch.mmu.root_level == 4) + audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4); + else + for (i = 0; i < 4; ++i) + if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK) + audit_mappings_page(vcpu, + vcpu->arch.mmu.pae_root[i], + i << 30, + 2); +} + +static int count_rmaps(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_memslots *slots; + int nmaps = 0; + int i, j, k, idx; + + idx = srcu_read_lock(&kvm->srcu); + slots = kvm_memslots(kvm); + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *m = &slots->memslots[i]; + struct kvm_rmap_desc *d; + + for (j = 0; j < m->npages; ++j) { + unsigned long *rmapp = &m->rmap[j]; + + if (!*rmapp) + continue; + if (!(*rmapp & 1)) { + ++nmaps; + continue; + } + d = (struct kvm_rmap_desc *)(*rmapp & ~1ul); + while (d) { + for (k = 0; k < RMAP_EXT; ++k) + if (d->sptes[k]) + ++nmaps; + else + break; + d = d->more; + } + } + } + srcu_read_unlock(&kvm->srcu, idx); + return nmaps; +} + +void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) +{ + unsigned long *rmapp; + struct kvm_mmu_page *rev_sp; + gfn_t gfn; + + if (is_writable_pte(*sptep)) { + rev_sp = page_header(__pa(sptep)); + gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt); + + if (!gfn_to_memslot(kvm, gfn)) { + if (!printk_ratelimit()) + return; + printk(KERN_ERR "%s: no memslot for gfn %ld\n", + audit_msg, gfn); + printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n", + audit_msg, (long int)(sptep - rev_sp->spt), + rev_sp->gfn); + dump_stack(); + return; + } + + rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level); + if (!*rmapp) { + if (!printk_ratelimit()) + return; + printk(KERN_ERR "%s: no rmap for writable spte %llx\n", + audit_msg, *sptep); + dump_stack(); + } + } + +} + +void audit_writable_sptes_have_rmaps(struct kvm_vcpu *vcpu) +{ + mmu_spte_walk(vcpu, inspect_spte_has_rmap); +} + +static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *sp; + int i; + + list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) { + u64 *pt = sp->spt; + + if (sp->role.level != PT_PAGE_TABLE_LEVEL) + continue; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + u64 ent = pt[i]; + + if (!(ent & PT_PRESENT_MASK)) + continue; + if (!is_writable_pte(ent)) + continue; + inspect_spte_has_rmap(vcpu->kvm, &pt[i]); + } + } + return; +} + +static void audit_rmap(struct kvm_vcpu *vcpu) +{ + check_writable_mappings_rmap(vcpu); + count_rmaps(vcpu); +} + +static void audit_write_protection(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *sp; + struct kvm_memory_slot *slot; + unsigned long *rmapp; + u64 *spte; + gfn_t gfn; + + list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) { + if (sp->role.direct) + continue; + if (sp->unsync) + continue; + + slot = gfn_to_memslot(vcpu->kvm, sp->gfn); + rmapp = &slot->rmap[gfn - slot->base_gfn]; + + spte = rmap_next(vcpu->kvm, rmapp, NULL); + while (spte) { + if (is_writable_pte(*spte)) + printk(KERN_ERR "%s: (%s) shadow page has " + "writable mappings: gfn %lx role %x\n", + __func__, audit_msg, sp->gfn, + sp->role.word); + spte = rmap_next(vcpu->kvm, rmapp, spte); + } + } +} + +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) +{ + int olddbg = dbg; + + dbg = 0; + audit_msg = msg; + audit_rmap(vcpu); + audit_write_protection(vcpu); + if (strcmp("pre pte write", audit_msg) != 0) + audit_mappings(vcpu); + audit_writable_sptes_have_rmaps(vcpu); + dbg = olddbg; +} + +#endif diff --git a/trunk/arch/x86/kvm/mmu.h b/trunk/arch/x86/kvm/mmu.h index 7086ca85d3e7..be66759321a5 100644 --- a/trunk/arch/x86/kvm/mmu.h +++ b/trunk/arch/x86/kvm/mmu.h @@ -49,17 +49,10 @@ #define PFERR_FETCH_MASK (1U << 4) int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]); -int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context); - -static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) -{ - return kvm->arch.n_max_mmu_pages - - kvm->arch.n_used_mmu_pages; -} static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) { - if (unlikely(kvm_mmu_available_pages(vcpu->kvm)< KVM_MIN_FREE_MMU_PAGES)) + if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) __kvm_mmu_free_some_pages(vcpu); } diff --git a/trunk/arch/x86/kvm/mmu_audit.c b/trunk/arch/x86/kvm/mmu_audit.c deleted file mode 100644 index ba2bcdde6221..000000000000 --- a/trunk/arch/x86/kvm/mmu_audit.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * mmu_audit.c: - * - * Audit code for KVM MMU - * - * Copyright (C) 2006 Qumranet, Inc. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. - * - * Authors: - * Yaniv Kamay - * Avi Kivity - * Marcelo Tosatti - * Xiao Guangrong - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include - -static int audit_point; - -#define audit_printk(fmt, args...) \ - printk(KERN_ERR "audit: (%s) error: " \ - fmt, audit_point_name[audit_point], ##args) - -typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level); - -static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, - inspect_spte_fn fn, int level) -{ - int i; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - u64 *ent = sp->spt; - - fn(vcpu, ent + i, level); - - if (is_shadow_present_pte(ent[i]) && - !is_last_spte(ent[i], level)) { - struct kvm_mmu_page *child; - - child = page_header(ent[i] & PT64_BASE_ADDR_MASK); - __mmu_spte_walk(vcpu, child, fn, level - 1); - } - } -} - -static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) -{ - int i; - struct kvm_mmu_page *sp; - - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) - return; - - if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) { - hpa_t root = vcpu->arch.mmu.root_hpa; - - sp = page_header(root); - __mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL); - return; - } - - for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; - - if (root && VALID_PAGE(root)) { - root &= PT64_BASE_ADDR_MASK; - sp = page_header(root); - __mmu_spte_walk(vcpu, sp, fn, 2); - } - } - - return; -} - -typedef void (*sp_handler) (struct kvm *kvm, struct kvm_mmu_page *sp); - -static void walk_all_active_sps(struct kvm *kvm, sp_handler fn) -{ - struct kvm_mmu_page *sp; - - list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) - fn(kvm, sp); -} - -static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) -{ - struct kvm_mmu_page *sp; - gfn_t gfn; - pfn_t pfn; - hpa_t hpa; - - sp = page_header(__pa(sptep)); - - if (sp->unsync) { - if (level != PT_PAGE_TABLE_LEVEL) { - audit_printk("unsync sp: %p level = %d\n", sp, level); - return; - } - - if (*sptep == shadow_notrap_nonpresent_pte) { - audit_printk("notrap spte in unsync sp: %p\n", sp); - return; - } - } - - if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) { - audit_printk("notrap spte in direct sp: %p\n", sp); - return; - } - - if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level)) - return; - - gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); - pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn); - - if (is_error_pfn(pfn)) { - kvm_release_pfn_clean(pfn); - return; - } - - hpa = pfn << PAGE_SHIFT; - if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) - audit_printk("levels %d pfn %llx hpa %llx ent %llxn", - vcpu->arch.mmu.root_level, pfn, hpa, *sptep); -} - -static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) -{ - unsigned long *rmapp; - struct kvm_mmu_page *rev_sp; - gfn_t gfn; - - - rev_sp = page_header(__pa(sptep)); - gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt); - - if (!gfn_to_memslot(kvm, gfn)) { - if (!printk_ratelimit()) - return; - audit_printk("no memslot for gfn %llx\n", gfn); - audit_printk("index %ld of sp (gfn=%llx)\n", - (long int)(sptep - rev_sp->spt), rev_sp->gfn); - dump_stack(); - return; - } - - rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level); - if (!*rmapp) { - if (!printk_ratelimit()) - return; - audit_printk("no rmap for writable spte %llx\n", *sptep); - dump_stack(); - } -} - -static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level) -{ - if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level)) - inspect_spte_has_rmap(vcpu->kvm, sptep); -} - -static void audit_spte_after_sync(struct kvm_vcpu *vcpu, u64 *sptep, int level) -{ - struct kvm_mmu_page *sp = page_header(__pa(sptep)); - - if (audit_point == AUDIT_POST_SYNC && sp->unsync) - audit_printk("meet unsync sp(%p) after sync root.\n", sp); -} - -static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) -{ - int i; - - if (sp->role.level != PT_PAGE_TABLE_LEVEL) - return; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - if (!is_rmap_spte(sp->spt[i])) - continue; - - inspect_spte_has_rmap(kvm, sp->spt + i); - } -} - -static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) -{ - struct kvm_memory_slot *slot; - unsigned long *rmapp; - u64 *spte; - - if (sp->role.direct || sp->unsync || sp->role.invalid) - return; - - slot = gfn_to_memslot(kvm, sp->gfn); - rmapp = &slot->rmap[sp->gfn - slot->base_gfn]; - - spte = rmap_next(kvm, rmapp, NULL); - while (spte) { - if (is_writable_pte(*spte)) - audit_printk("shadow page has writable mappings: gfn " - "%llx role %x\n", sp->gfn, sp->role.word); - spte = rmap_next(kvm, rmapp, spte); - } -} - -static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp) -{ - check_mappings_rmap(kvm, sp); - audit_write_protection(kvm, sp); -} - -static void audit_all_active_sps(struct kvm *kvm) -{ - walk_all_active_sps(kvm, audit_sp); -} - -static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level) -{ - audit_sptes_have_rmaps(vcpu, sptep, level); - audit_mappings(vcpu, sptep, level); - audit_spte_after_sync(vcpu, sptep, level); -} - -static void audit_vcpu_spte(struct kvm_vcpu *vcpu) -{ - mmu_spte_walk(vcpu, audit_spte); -} - -static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int point) -{ - static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); - - if (!__ratelimit(&ratelimit_state)) - return; - - audit_point = point; - audit_all_active_sps(vcpu->kvm); - audit_vcpu_spte(vcpu); -} - -static bool mmu_audit; - -static void mmu_audit_enable(void) -{ - int ret; - - if (mmu_audit) - return; - - ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); - WARN_ON(ret); - - mmu_audit = true; -} - -static void mmu_audit_disable(void) -{ - if (!mmu_audit) - return; - - unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); - tracepoint_synchronize_unregister(); - mmu_audit = false; -} - -static int mmu_audit_set(const char *val, const struct kernel_param *kp) -{ - int ret; - unsigned long enable; - - ret = strict_strtoul(val, 10, &enable); - if (ret < 0) - return -EINVAL; - - switch (enable) { - case 0: - mmu_audit_disable(); - break; - case 1: - mmu_audit_enable(); - break; - default: - return -EINVAL; - } - - return 0; -} - -static struct kernel_param_ops audit_param_ops = { - .set = mmu_audit_set, - .get = param_get_bool, -}; - -module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644); diff --git a/trunk/arch/x86/kvm/mmutrace.h b/trunk/arch/x86/kvm/mmutrace.h index b60b4fdb3eda..3aab0f0930ef 100644 --- a/trunk/arch/x86/kvm/mmutrace.h +++ b/trunk/arch/x86/kvm/mmutrace.h @@ -195,25 +195,6 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page, TP_ARGS(sp) ); - -TRACE_EVENT( - kvm_mmu_audit, - TP_PROTO(struct kvm_vcpu *vcpu, int audit_point), - TP_ARGS(vcpu, audit_point), - - TP_STRUCT__entry( - __field(struct kvm_vcpu *, vcpu) - __field(int, audit_point) - ), - - TP_fast_assign( - __entry->vcpu = vcpu; - __entry->audit_point = audit_point; - ), - - TP_printk("vcpu:%d %s", __entry->vcpu->cpu, - audit_point_name[__entry->audit_point]) -); #endif /* _TRACE_KVMMMU_H */ #undef TRACE_INCLUDE_PATH diff --git a/trunk/arch/x86/kvm/paging_tmpl.h b/trunk/arch/x86/kvm/paging_tmpl.h index cd7a833a3b52..51ef9097960d 100644 --- a/trunk/arch/x86/kvm/paging_tmpl.h +++ b/trunk/arch/x86/kvm/paging_tmpl.h @@ -7,7 +7,7 @@ * MMU support * * Copyright (C) 2006 Qumranet, Inc. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Authors: * Yaniv Kamay @@ -67,7 +67,6 @@ struct guest_walker { int level; gfn_t table_gfn[PT_MAX_FULL_LEVELS]; pt_element_t ptes[PT_MAX_FULL_LEVELS]; - pt_element_t prefetch_ptes[PTE_PREFETCH_NUM]; gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; unsigned pt_access; unsigned pte_access; @@ -105,7 +104,7 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; #if PTTYPE == 64 - if (vcpu->arch.mmu.nx) + if (is_nx(vcpu)) access &= ~(gpte >> PT64_NX_SHIFT); #endif return access; @@ -114,32 +113,26 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) /* * Fetch a guest pte for a guest virtual address */ -static int FNAME(walk_addr_generic)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gva_t addr, u32 access) +static int FNAME(walk_addr)(struct guest_walker *walker, + struct kvm_vcpu *vcpu, gva_t addr, + int write_fault, int user_fault, int fetch_fault) { pt_element_t pte; gfn_t table_gfn; unsigned index, pt_access, uninitialized_var(pte_access); gpa_t pte_gpa; bool eperm, present, rsvd_fault; - int offset, write_fault, user_fault, fetch_fault; - - write_fault = access & PFERR_WRITE_MASK; - user_fault = access & PFERR_USER_MASK; - fetch_fault = access & PFERR_FETCH_MASK; trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault, fetch_fault); walk: present = true; eperm = rsvd_fault = false; - walker->level = mmu->root_level; - pte = mmu->get_cr3(vcpu); - + walker->level = vcpu->arch.mmu.root_level; + pte = vcpu->arch.cr3; #if PTTYPE == 64 - if (walker->level == PT32E_ROOT_LEVEL) { - pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3); + if (!is_long_mode(vcpu)) { + pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3); trace_kvm_mmu_paging_element(pte, walker->level); if (!is_present_gpte(pte)) { present = false; @@ -149,7 +142,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, } #endif ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || - (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0); + (vcpu->arch.cr3 & CR3_NONPAE_RESERVED_BITS) == 0); pt_access = ACC_ALL; @@ -157,14 +150,12 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, index = PT_INDEX(addr, walker->level); table_gfn = gpte_to_gfn(pte); - offset = index * sizeof(pt_element_t); - pte_gpa = gfn_to_gpa(table_gfn) + offset; + pte_gpa = gfn_to_gpa(table_gfn); + pte_gpa += index * sizeof(pt_element_t); walker->table_gfn[walker->level - 1] = table_gfn; walker->pte_gpa[walker->level - 1] = pte_gpa; - if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte, - offset, sizeof(pte), - PFERR_USER_MASK|PFERR_WRITE_MASK)) { + if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) { present = false; break; } @@ -176,7 +167,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, break; } - if (is_rsvd_bits_set(&vcpu->arch.mmu, pte, walker->level)) { + if (is_rsvd_bits_set(vcpu, pte, walker->level)) { rsvd_fault = true; break; } @@ -213,28 +204,17 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, (PTTYPE == 64 || is_pse(vcpu))) || ((walker->level == PT_PDPE_LEVEL) && is_large_pte(pte) && - mmu->root_level == PT64_ROOT_LEVEL)) { + is_long_mode(vcpu))) { int lvl = walker->level; - gpa_t real_gpa; - gfn_t gfn; - u32 ac; - gfn = gpte_to_gfn_lvl(pte, lvl); - gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT; + walker->gfn = gpte_to_gfn_lvl(pte, lvl); + walker->gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) + >> PAGE_SHIFT; if (PTTYPE == 32 && walker->level == PT_DIRECTORY_LEVEL && is_cpuid_PSE36()) - gfn += pse36_gfn_delta(pte); - - ac = write_fault | fetch_fault | user_fault; - - real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn), - ac); - if (real_gpa == UNMAPPED_GVA) - return 0; - - walker->gfn = real_gpa >> PAGE_SHIFT; + walker->gfn += pse36_gfn_delta(pte); break; } @@ -269,36 +249,18 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->error_code = 0; if (present) walker->error_code |= PFERR_PRESENT_MASK; - - walker->error_code |= write_fault | user_fault; - - if (fetch_fault && mmu->nx) + if (write_fault) + walker->error_code |= PFERR_WRITE_MASK; + if (user_fault) + walker->error_code |= PFERR_USER_MASK; + if (fetch_fault && is_nx(vcpu)) walker->error_code |= PFERR_FETCH_MASK; if (rsvd_fault) walker->error_code |= PFERR_RSVD_MASK; - - vcpu->arch.fault.address = addr; - vcpu->arch.fault.error_code = walker->error_code; - trace_kvm_mmu_walker_error(walker->error_code); return 0; } -static int FNAME(walk_addr)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, gva_t addr, u32 access) -{ - return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.mmu, addr, - access); -} - -static int FNAME(walk_addr_nested)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, gva_t addr, - u32 access) -{ - return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.nested_mmu, - addr, access); -} - static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, const void *pte) { @@ -340,87 +302,14 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu, struct guest_walker *gw, int level) { + int r; pt_element_t curr_pte; - gpa_t base_gpa, pte_gpa = gw->pte_gpa[level - 1]; - u64 mask; - int r, index; - - if (level == PT_PAGE_TABLE_LEVEL) { - mask = PTE_PREFETCH_NUM * sizeof(pt_element_t) - 1; - base_gpa = pte_gpa & ~mask; - index = (pte_gpa - base_gpa) / sizeof(pt_element_t); - - r = kvm_read_guest_atomic(vcpu->kvm, base_gpa, - gw->prefetch_ptes, sizeof(gw->prefetch_ptes)); - curr_pte = gw->prefetch_ptes[index]; - } else - r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, - &curr_pte, sizeof(curr_pte)); + r = kvm_read_guest_atomic(vcpu->kvm, gw->pte_gpa[level - 1], + &curr_pte, sizeof(curr_pte)); return r || curr_pte != gw->ptes[level - 1]; } -static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, - u64 *sptep) -{ - struct kvm_mmu_page *sp; - struct kvm_mmu *mmu = &vcpu->arch.mmu; - pt_element_t *gptep = gw->prefetch_ptes; - u64 *spte; - int i; - - sp = page_header(__pa(sptep)); - - if (sp->role.level > PT_PAGE_TABLE_LEVEL) - return; - - if (sp->role.direct) - return __direct_pte_prefetch(vcpu, sp, sptep); - - i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1); - spte = sp->spt + i; - - for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) { - pt_element_t gpte; - unsigned pte_access; - gfn_t gfn; - pfn_t pfn; - bool dirty; - - if (spte == sptep) - continue; - - if (*spte != shadow_trap_nonpresent_pte) - continue; - - gpte = gptep[i]; - - if (!is_present_gpte(gpte) || - is_rsvd_bits_set(mmu, gpte, PT_PAGE_TABLE_LEVEL)) { - if (!sp->unsync) - __set_spte(spte, shadow_notrap_nonpresent_pte); - continue; - } - - if (!(gpte & PT_ACCESSED_MASK)) - continue; - - pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); - gfn = gpte_to_gfn(gpte); - dirty = is_dirty_gpte(gpte); - pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, - (pte_access & ACC_WRITE_MASK) && dirty); - if (is_error_pfn(pfn)) { - kvm_release_pfn_clean(pfn); - break; - } - - mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, - dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn, - pfn, true, true); - } -} - /* * Fetch a shadow pte for a specific level in the paging hierarchy. */ @@ -502,7 +391,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access, user_fault, write_fault, dirty, ptwrite, it.level, gw->gfn, pfn, false, true); - FNAME(pte_prefetch)(vcpu, gw, it.sptep); return it.sptep; @@ -532,6 +420,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, { int write_fault = error_code & PFERR_WRITE_MASK; int user_fault = error_code & PFERR_USER_MASK; + int fetch_fault = error_code & PFERR_FETCH_MASK; struct guest_walker walker; u64 *sptep; int write_pt = 0; @@ -541,6 +430,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, unsigned long mmu_seq; pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code); + kvm_mmu_audit(vcpu, "pre page fault"); r = mmu_topup_memory_caches(vcpu); if (r) @@ -549,14 +439,15 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, /* * Look up the guest pte for the faulting address. */ - r = FNAME(walk_addr)(&walker, vcpu, addr, error_code); + r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault, + fetch_fault); /* * The page is not mapped by the guest. Let the guest handle it. */ if (!r) { pgprintk("%s: guest page fault\n", __func__); - inject_page_fault(vcpu); + inject_page_fault(vcpu, addr, walker.error_code); vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ return 0; } @@ -577,8 +468,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu, mmu_seq)) goto out_unlock; - - trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT); kvm_mmu_free_some_pages(vcpu); sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, level, &write_pt, pfn); @@ -590,7 +479,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ ++vcpu->stat.pf_fixed; - trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT); + kvm_mmu_audit(vcpu, "post page fault (fixed)"); spin_unlock(&vcpu->kvm->mmu_lock); return write_pt; @@ -667,25 +556,10 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, gpa_t gpa = UNMAPPED_GVA; int r; - r = FNAME(walk_addr)(&walker, vcpu, vaddr, access); - - if (r) { - gpa = gfn_to_gpa(walker.gfn); - gpa |= vaddr & ~PAGE_MASK; - } else if (error) - *error = walker.error_code; - - return gpa; -} - -static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr, - u32 access, u32 *error) -{ - struct guest_walker walker; - gpa_t gpa = UNMAPPED_GVA; - int r; - - r = FNAME(walk_addr_nested)(&walker, vcpu, vaddr, access); + r = FNAME(walk_addr)(&walker, vcpu, vaddr, + !!(access & PFERR_WRITE_MASK), + !!(access & PFERR_USER_MASK), + !!(access & PFERR_FETCH_MASK)); if (r) { gpa = gfn_to_gpa(walker.gfn); @@ -764,7 +638,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, return -EINVAL; gfn = gpte_to_gfn(gpte); - if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL) + if (is_rsvd_bits_set(vcpu, gpte, PT_PAGE_TABLE_LEVEL) || gfn != sp->gfns[i] || !is_present_gpte(gpte) || !(gpte & PT_ACCESSED_MASK)) { u64 nonpresent; diff --git a/trunk/arch/x86/kvm/svm.c b/trunk/arch/x86/kvm/svm.c index 82e144a4e514..8a3f9f64f86f 100644 --- a/trunk/arch/x86/kvm/svm.c +++ b/trunk/arch/x86/kvm/svm.c @@ -4,7 +4,7 @@ * AMD SVM support * * Copyright (C) 2006 Qumranet, Inc. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Authors: * Yaniv Kamay @@ -88,14 +88,6 @@ struct nested_state { /* A VMEXIT is required but not yet emulated */ bool exit_required; - /* - * If we vmexit during an instruction emulation we need this to restore - * the l1 guest rip after the emulation - */ - unsigned long vmexit_rip; - unsigned long vmexit_rsp; - unsigned long vmexit_rax; - /* cache for intercepts of the guest */ u16 intercept_cr_read; u16 intercept_cr_write; @@ -104,8 +96,6 @@ struct nested_state { u32 intercept_exceptions; u64 intercept; - /* Nested Paging related state */ - u64 nested_cr3; }; #define MSRPM_OFFSETS 16 @@ -294,15 +284,6 @@ static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) force_new_asid(vcpu); } -static int get_npt_level(void) -{ -#ifdef CONFIG_X86_64 - return PT64_ROOT_LEVEL; -#else - return PT32E_ROOT_LEVEL; -#endif -} - static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) { vcpu->arch.efer = efer; @@ -720,29 +701,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) seg->base = 0; } -static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) -{ - struct vcpu_svm *svm = to_svm(vcpu); - u64 g_tsc_offset = 0; - - if (is_nested(svm)) { - g_tsc_offset = svm->vmcb->control.tsc_offset - - svm->nested.hsave->control.tsc_offset; - svm->nested.hsave->control.tsc_offset = offset; - } - - svm->vmcb->control.tsc_offset = offset + g_tsc_offset; -} - -static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->control.tsc_offset += adjustment; - if (is_nested(svm)) - svm->nested.hsave->control.tsc_offset += adjustment; -} - static void init_vmcb(struct vcpu_svm *svm) { struct vmcb_control_area *control = &svm->vmcb->control; @@ -835,7 +793,7 @@ static void init_vmcb(struct vcpu_svm *svm) init_sys_seg(&save->ldtr, SEG_TYPE_LDT); init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); - svm_set_efer(&svm->vcpu, 0); + save->efer = EFER_SVME; save->dr6 = 0xffff0ff0; save->dr7 = 0x400; save->rflags = 2; @@ -846,8 +804,8 @@ static void init_vmcb(struct vcpu_svm *svm) * This is the guest-visible cr0 value. * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0. */ - svm->vcpu.arch.cr0 = 0; - (void)kvm_set_cr0(&svm->vcpu, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET); + svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET; + (void)kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0); save->cr4 = X86_CR4_PAE; /* rdx = ?? */ @@ -943,7 +901,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; svm->asid_generation = 0; init_vmcb(svm); - kvm_write_tsc(&svm->vcpu, 0); + svm->vmcb->control.tsc_offset = 0-native_read_tsc(); err = fx_init(&svm->vcpu); if (err) @@ -989,6 +947,20 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) int i; if (unlikely(cpu != vcpu->cpu)) { + u64 delta; + + if (check_tsc_unstable()) { + /* + * Make sure that the guest sees a monotonically + * increasing TSC. + */ + delta = vcpu->arch.host_tsc - native_read_tsc(); + svm->vmcb->control.tsc_offset += delta; + if (is_nested(svm)) + svm->nested.hsave->control.tsc_offset += delta; + } + vcpu->cpu = cpu; + kvm_migrate_timers(vcpu); svm->asid_generation = 0; } @@ -1004,6 +976,8 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) ++vcpu->stat.host_state_reload; for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); + + vcpu->arch.host_tsc = native_read_tsc(); } static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) @@ -1021,7 +995,7 @@ static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) switch (reg) { case VCPU_EXREG_PDPTR: BUG_ON(!npt_enabled); - load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3); + load_pdptrs(vcpu, vcpu->arch.cr3); break; default: BUG(); @@ -1232,12 +1206,8 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) if (old == new) { /* cr0 write with ts and mp unchanged */ svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE; - if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) { - svm->nested.vmexit_rip = kvm_rip_read(vcpu); - svm->nested.vmexit_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP); - svm->nested.vmexit_rax = kvm_register_read(vcpu, VCPU_REGS_RAX); + if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) return; - } } } @@ -1611,54 +1581,6 @@ static int vmmcall_interception(struct vcpu_svm *svm) return 1; } -static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - return svm->nested.nested_cr3; -} - -static void nested_svm_set_tdp_cr3(struct kvm_vcpu *vcpu, - unsigned long root) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->control.nested_cr3 = root; - force_new_asid(vcpu); -} - -static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->control.exit_code = SVM_EXIT_NPF; - svm->vmcb->control.exit_code_hi = 0; - svm->vmcb->control.exit_info_1 = vcpu->arch.fault.error_code; - svm->vmcb->control.exit_info_2 = vcpu->arch.fault.address; - - nested_svm_vmexit(svm); -} - -static int nested_svm_init_mmu_context(struct kvm_vcpu *vcpu) -{ - int r; - - r = kvm_init_shadow_mmu(vcpu, &vcpu->arch.mmu); - - vcpu->arch.mmu.set_cr3 = nested_svm_set_tdp_cr3; - vcpu->arch.mmu.get_cr3 = nested_svm_get_tdp_cr3; - vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit; - vcpu->arch.mmu.shadow_root_level = get_npt_level(); - vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu; - - return r; -} - -static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu) -{ - vcpu->arch.walk_mmu = &vcpu->arch.mmu; -} - static int nested_svm_check_permissions(struct vcpu_svm *svm) { if (!(svm->vcpu.arch.efer & EFER_SVME) @@ -1707,14 +1629,6 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm) if (!(svm->vcpu.arch.hflags & HF_HIF_MASK)) return false; - /* - * if vmexit was already requested (by intercepted exception - * for instance) do not overwrite it with "external interrupt" - * vmexit. - */ - if (svm->nested.exit_required) - return false; - svm->vmcb->control.exit_code = SVM_EXIT_INTR; svm->vmcb->control.exit_info_1 = 0; svm->vmcb->control.exit_info_2 = 0; @@ -1982,7 +1896,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) nested_vmcb->save.ds = vmcb->save.ds; nested_vmcb->save.gdtr = vmcb->save.gdtr; nested_vmcb->save.idtr = vmcb->save.idtr; - nested_vmcb->save.efer = svm->vcpu.arch.efer; nested_vmcb->save.cr0 = kvm_read_cr0(&svm->vcpu); nested_vmcb->save.cr3 = svm->vcpu.arch.cr3; nested_vmcb->save.cr2 = vmcb->save.cr2; @@ -2004,7 +1917,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2; nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info; nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err; - nested_vmcb->control.next_rip = vmcb->control.next_rip; /* * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have @@ -2035,8 +1947,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) kvm_clear_exception_queue(&svm->vcpu); kvm_clear_interrupt_queue(&svm->vcpu); - svm->nested.nested_cr3 = 0; - /* Restore selected save entries */ svm->vmcb->save.es = hsave->save.es; svm->vmcb->save.cs = hsave->save.cs; @@ -2063,7 +1973,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) nested_svm_unmap(page); - nested_svm_uninit_mmu_context(&svm->vcpu); kvm_mmu_reset_context(&svm->vcpu); kvm_mmu_load(&svm->vcpu); @@ -2103,20 +2012,6 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) return true; } -static bool nested_vmcb_checks(struct vmcb *vmcb) -{ - if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0) - return false; - - if (vmcb->control.asid == 0) - return false; - - if (vmcb->control.nested_ctl && !npt_enabled) - return false; - - return true; -} - static bool nested_svm_vmrun(struct vcpu_svm *svm) { struct vmcb *nested_vmcb; @@ -2131,18 +2026,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) if (!nested_vmcb) return false; - if (!nested_vmcb_checks(nested_vmcb)) { - nested_vmcb->control.exit_code = SVM_EXIT_ERR; - nested_vmcb->control.exit_code_hi = 0; - nested_vmcb->control.exit_info_1 = 0; - nested_vmcb->control.exit_info_2 = 0; - - nested_svm_unmap(page); - - return false; - } - - trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa, + trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, vmcb_gpa, nested_vmcb->save.rip, nested_vmcb->control.int_ctl, nested_vmcb->control.event_inj, @@ -2171,7 +2055,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) hsave->save.cr0 = kvm_read_cr0(&svm->vcpu); hsave->save.cr4 = svm->vcpu.arch.cr4; hsave->save.rflags = vmcb->save.rflags; - hsave->save.rip = kvm_rip_read(&svm->vcpu); + hsave->save.rip = svm->next_rip; hsave->save.rsp = vmcb->save.rsp; hsave->save.rax = vmcb->save.rax; if (npt_enabled) @@ -2186,12 +2070,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) else svm->vcpu.arch.hflags &= ~HF_HIF_MASK; - if (nested_vmcb->control.nested_ctl) { - kvm_mmu_unload(&svm->vcpu); - svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3; - nested_svm_init_mmu_context(&svm->vcpu); - } - /* Load the nested guest state */ svm->vmcb->save.es = nested_vmcb->save.es; svm->vmcb->save.cs = nested_vmcb->save.cs; @@ -2349,8 +2227,8 @@ static int vmrun_interception(struct vcpu_svm *svm) if (nested_svm_check_permissions(svm)) return 1; - /* Save rip after vmrun instruction */ - kvm_rip_write(&svm->vcpu, kvm_rip_read(&svm->vcpu) + 3); + svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; + skip_emulated_instruction(&svm->vcpu); if (!nested_svm_vmrun(svm)) return 1; @@ -2379,7 +2257,6 @@ static int stgi_interception(struct vcpu_svm *svm) svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; skip_emulated_instruction(&svm->vcpu); - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); enable_gif(svm); @@ -2522,23 +2399,6 @@ static int emulate_on_interception(struct vcpu_svm *svm) return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE; } -static int cr0_write_interception(struct vcpu_svm *svm) -{ - struct kvm_vcpu *vcpu = &svm->vcpu; - int r; - - r = emulate_instruction(&svm->vcpu, 0, 0, 0); - - if (svm->nested.vmexit_rip) { - kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip); - kvm_register_write(vcpu, VCPU_REGS_RSP, svm->nested.vmexit_rsp); - kvm_register_write(vcpu, VCPU_REGS_RAX, svm->nested.vmexit_rax); - svm->nested.vmexit_rip = 0; - } - - return r == EMULATE_DONE; -} - static int cr8_write_interception(struct vcpu_svm *svm) { struct kvm_run *kvm_run = svm->vcpu.run; @@ -2682,9 +2542,20 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) struct vcpu_svm *svm = to_svm(vcpu); switch (ecx) { - case MSR_IA32_TSC: - kvm_write_tsc(vcpu, data); + case MSR_IA32_TSC: { + u64 tsc_offset = data - native_read_tsc(); + u64 g_tsc_offset = 0; + + if (is_nested(svm)) { + g_tsc_offset = svm->vmcb->control.tsc_offset - + svm->nested.hsave->control.tsc_offset; + svm->nested.hsave->control.tsc_offset = tsc_offset; + } + + svm->vmcb->control.tsc_offset = tsc_offset + g_tsc_offset; + break; + } case MSR_STAR: svm->vmcb->save.star = data; break; @@ -2772,7 +2643,6 @@ static int interrupt_window_interception(struct vcpu_svm *svm) { struct kvm_run *kvm_run = svm->vcpu.run; - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); svm_clear_vintr(svm); svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; /* @@ -2802,7 +2672,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR4] = emulate_on_interception, [SVM_EXIT_READ_CR8] = emulate_on_interception, [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, - [SVM_EXIT_WRITE_CR0] = cr0_write_interception, + [SVM_EXIT_WRITE_CR0] = emulate_on_interception, [SVM_EXIT_WRITE_CR3] = emulate_on_interception, [SVM_EXIT_WRITE_CR4] = emulate_on_interception, [SVM_EXIT_WRITE_CR8] = cr8_write_interception, @@ -3001,8 +2871,7 @@ static int handle_exit(struct kvm_vcpu *vcpu) if (is_external_interrupt(svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR && - exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH && - exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI) + exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " "exit_code 0x%x\n", __func__, svm->vmcb->control.exit_int_info, @@ -3219,10 +3088,8 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) svm->int3_injected = 0; - if (svm->vcpu.arch.hflags & HF_IRET_MASK) { + if (svm->vcpu.arch.hflags & HF_IRET_MASK) svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); - } svm->vcpu.arch.nmi_injected = false; kvm_clear_exception_queue(&svm->vcpu); @@ -3231,8 +3098,6 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) if (!(exitintinfo & SVM_EXITINTINFO_VALID)) return; - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); - vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; @@ -3269,17 +3134,6 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) } } -static void svm_cancel_injection(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - struct vmcb_control_area *control = &svm->vmcb->control; - - control->exit_int_info = control->event_inj; - control->exit_int_info_err = control->event_inj_err; - control->event_inj = 0; - svm_complete_interrupts(svm); -} - #ifdef CONFIG_X86_64 #define R "r" #else @@ -3313,6 +3167,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) savesegment(gs, gs_selector); ldt_selector = kvm_read_ldt(); svm->vmcb->save.cr2 = vcpu->arch.cr2; + /* required for live migration with NPT */ + if (npt_enabled) + svm->vmcb->save.cr3 = vcpu->arch.cr3; clgi(); @@ -3434,19 +3291,13 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) { struct vcpu_svm *svm = to_svm(vcpu); - svm->vmcb->save.cr3 = root; - force_new_asid(vcpu); -} - -static void set_tdp_cr3(struct kvm_vcpu *vcpu, unsigned long root) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->control.nested_cr3 = root; - - /* Also sync guest cr3 here in case we live migrate */ - svm->vmcb->save.cr3 = vcpu->arch.cr3; + if (npt_enabled) { + svm->vmcb->control.nested_cr3 = root; + force_new_asid(vcpu); + return; + } + svm->vmcb->save.cr3 = root; force_new_asid(vcpu); } @@ -3482,6 +3333,15 @@ static bool svm_cpu_has_accelerated_tpr(void) return false; } +static int get_npt_level(void) +{ +#ifdef CONFIG_X86_64 + return PT64_ROOT_LEVEL; +#else + return PT32E_ROOT_LEVEL; +#endif +} + static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) { return 0; @@ -3494,25 +3354,12 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu) static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) { switch (func) { - case 0x80000001: - if (nested) - entry->ecx |= (1 << 2); /* Set SVM bit */ - break; case 0x8000000A: entry->eax = 1; /* SVM revision 1 */ entry->ebx = 8; /* Lets support 8 ASIDs in case we add proper ASID emulation to nested SVM */ entry->ecx = 0; /* Reserved */ - entry->edx = 0; /* Per default do not support any - additional features */ - - /* Support next_rip if host supports it */ - if (svm_has(SVM_FEATURE_NRIP)) - entry->edx |= SVM_FEATURE_NRIP; - - /* Support NPT for the guest if enabled */ - if (npt_enabled) - entry->edx |= SVM_FEATURE_NPT; + entry->edx = 0; /* Do not support any additional features */ break; } @@ -3650,7 +3497,6 @@ static struct kvm_x86_ops svm_x86_ops = { .set_irq = svm_set_irq, .set_nmi = svm_inject_nmi, .queue_exception = svm_queue_exception, - .cancel_injection = svm_cancel_injection, .interrupt_allowed = svm_interrupt_allowed, .nmi_allowed = svm_nmi_allowed, .get_nmi_mask = svm_get_nmi_mask, @@ -3673,11 +3519,6 @@ static struct kvm_x86_ops svm_x86_ops = { .set_supported_cpuid = svm_set_supported_cpuid, .has_wbinvd_exit = svm_has_wbinvd_exit, - - .write_tsc_offset = svm_write_tsc_offset, - .adjust_tsc_offset = svm_adjust_tsc_offset, - - .set_tdp_cr3 = set_tdp_cr3, }; static int __init svm_init(void) diff --git a/trunk/arch/x86/kvm/timer.c b/trunk/arch/x86/kvm/timer.c index fc7a101c4a35..e16a0dbe74d8 100644 --- a/trunk/arch/x86/kvm/timer.c +++ b/trunk/arch/x86/kvm/timer.c @@ -6,7 +6,7 @@ * * timer support * - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. diff --git a/trunk/arch/x86/kvm/vmx.c b/trunk/arch/x86/kvm/vmx.c index 8da0e45ff7c9..7bddfab12013 100644 --- a/trunk/arch/x86/kvm/vmx.c +++ b/trunk/arch/x86/kvm/vmx.c @@ -5,7 +5,7 @@ * machines without emulation or binary translation. * * Copyright (C) 2006 Qumranet, Inc. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Authors: * Avi Kivity @@ -125,7 +125,6 @@ struct vcpu_vmx { unsigned long host_rsp; int launched; u8 fail; - u32 exit_intr_info; u32 idt_vectoring_info; struct shared_msr_entry *guest_msrs; int nmsrs; @@ -155,6 +154,11 @@ struct vcpu_vmx { u32 limit; u32 ar; } tr, es, ds, fs, gs; + struct { + bool pending; + u8 vector; + unsigned rip; + } irq; } rmode; int vpid; bool emulation_required; @@ -501,6 +505,7 @@ static void __vcpu_clear(void *arg) vmcs_clear(vmx->vmcs); if (per_cpu(current_vmcs, cpu) == vmx->vmcs) per_cpu(current_vmcs, cpu) = NULL; + rdtscll(vmx->vcpu.arch.host_tsc); list_del(&vmx->local_vcpus_link); vmx->vcpu.cpu = -1; vmx->launched = 0; @@ -701,10 +706,11 @@ static void reload_tss(void) /* * VT restores TR but not its size. Useless. */ - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr gdt; struct desc_struct *descs; - descs = (void *)gdt->address; + native_store_gdt(&gdt); + descs = (void *)gdt.address; descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ load_TR_desc(); } @@ -747,7 +753,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) static unsigned long segment_base(u16 selector) { - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr gdt; struct desc_struct *d; unsigned long table_base; unsigned long v; @@ -755,7 +761,8 @@ static unsigned long segment_base(u16 selector) if (!(selector & ~3)) return 0; - table_base = gdt->address; + native_store_gdt(&gdt); + table_base = gdt.address; if (selector & 4) { /* from ldt */ u16 ldt_selector = kvm_read_ldt(); @@ -876,6 +883,7 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx) static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + u64 tsc_this, delta, new_offset; u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); if (!vmm_exclusive) @@ -889,24 +897,37 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } if (vcpu->cpu != cpu) { - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr dt; unsigned long sysenter_esp; + kvm_migrate_timers(vcpu); kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); local_irq_disable(); list_add(&vmx->local_vcpus_link, &per_cpu(vcpus_on_cpu, cpu)); local_irq_enable(); + vcpu->cpu = cpu; /* * Linux uses per-cpu TSS and GDT, so set these when switching * processors. */ vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */ - vmcs_writel(HOST_GDTR_BASE, gdt->address); /* 22.2.4 */ + native_store_gdt(&dt); + vmcs_writel(HOST_GDTR_BASE, dt.address); /* 22.2.4 */ rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ + + /* + * Make sure the time stamp counter is monotonous. + */ + rdtscll(tsc_this); + if (tsc_this < vcpu->arch.host_tsc) { + delta = vcpu->arch.host_tsc - tsc_this; + new_offset = vmcs_read64(TSC_OFFSET) + delta; + vmcs_write64(TSC_OFFSET, new_offset); + } } } @@ -1023,8 +1044,16 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, } if (vmx->rmode.vm86_active) { - if (kvm_inject_realmode_interrupt(vcpu, nr) != EMULATE_DONE) - kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + vmx->rmode.irq.pending = true; + vmx->rmode.irq.vector = nr; + vmx->rmode.irq.rip = kvm_rip_read(vcpu); + if (kvm_exception_is_soft(nr)) + vmx->rmode.irq.rip += + vmx->vcpu.arch.event_exit_inst_len; + intr_info |= INTR_TYPE_SOFT_INTR; + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); + kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); return; } @@ -1120,17 +1149,12 @@ static u64 guest_read_tsc(void) } /* - * writes 'offset' into guest's timestamp counter offset register + * writes 'guest_tsc' into guest's timestamp counter "register" + * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc */ -static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) -{ - vmcs_write64(TSC_OFFSET, offset); -} - -static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment) +static void guest_write_tsc(u64 guest_tsc, u64 host_tsc) { - u64 offset = vmcs_read64(TSC_OFFSET); - vmcs_write64(TSC_OFFSET, offset + adjustment); + vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); } /* @@ -1203,6 +1227,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct shared_msr_entry *msr; + u64 host_tsc; int ret = 0; switch (msr_index) { @@ -1232,7 +1257,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) vmcs_writel(GUEST_SYSENTER_ESP, data); break; case MSR_IA32_TSC: - kvm_write_tsc(vcpu, data); + rdtscll(host_tsc); + guest_write_tsc(data, host_tsc); break; case MSR_IA32_CR_PAT: if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { @@ -1830,20 +1856,20 @@ static void ept_load_pdptrs(struct kvm_vcpu *vcpu) return; if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) { - vmcs_write64(GUEST_PDPTR0, vcpu->arch.mmu.pdptrs[0]); - vmcs_write64(GUEST_PDPTR1, vcpu->arch.mmu.pdptrs[1]); - vmcs_write64(GUEST_PDPTR2, vcpu->arch.mmu.pdptrs[2]); - vmcs_write64(GUEST_PDPTR3, vcpu->arch.mmu.pdptrs[3]); + vmcs_write64(GUEST_PDPTR0, vcpu->arch.pdptrs[0]); + vmcs_write64(GUEST_PDPTR1, vcpu->arch.pdptrs[1]); + vmcs_write64(GUEST_PDPTR2, vcpu->arch.pdptrs[2]); + vmcs_write64(GUEST_PDPTR3, vcpu->arch.pdptrs[3]); } } static void ept_save_pdptrs(struct kvm_vcpu *vcpu) { if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) { - vcpu->arch.mmu.pdptrs[0] = vmcs_read64(GUEST_PDPTR0); - vcpu->arch.mmu.pdptrs[1] = vmcs_read64(GUEST_PDPTR1); - vcpu->arch.mmu.pdptrs[2] = vmcs_read64(GUEST_PDPTR2); - vcpu->arch.mmu.pdptrs[3] = vmcs_read64(GUEST_PDPTR3); + vcpu->arch.pdptrs[0] = vmcs_read64(GUEST_PDPTR0); + vcpu->arch.pdptrs[1] = vmcs_read64(GUEST_PDPTR1); + vcpu->arch.pdptrs[2] = vmcs_read64(GUEST_PDPTR2); + vcpu->arch.pdptrs[3] = vmcs_read64(GUEST_PDPTR3); } __set_bit(VCPU_EXREG_PDPTR, @@ -2489,7 +2515,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) { u32 host_sysenter_cs, msr_low, msr_high; u32 junk; - u64 host_pat; + u64 host_pat, tsc_this, tsc_base; unsigned long a; struct desc_ptr dt; int i; @@ -2630,7 +2656,12 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE; vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits); - kvm_write_tsc(&vmx->vcpu, 0); + tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc; + rdtscll(tsc_this); + if (tsc_this < vmx->vcpu.kvm->arch.vm_init_tsc) + tsc_base = tsc_this; + + guest_write_tsc(0, tsc_base); return 0; } @@ -2803,8 +2834,16 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu) ++vcpu->stat.irq_injections; if (vmx->rmode.vm86_active) { - if (kvm_inject_realmode_interrupt(vcpu, irq) != EMULATE_DONE) - kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + vmx->rmode.irq.pending = true; + vmx->rmode.irq.vector = irq; + vmx->rmode.irq.rip = kvm_rip_read(vcpu); + if (vcpu->arch.interrupt.soft) + vmx->rmode.irq.rip += + vmx->vcpu.arch.event_exit_inst_len; + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); + kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); return; } intr = irq | INTR_INFO_VALID_MASK; @@ -2836,8 +2875,14 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) ++vcpu->stat.nmi_injections; if (vmx->rmode.vm86_active) { - if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR) != EMULATE_DONE) - kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + vmx->rmode.irq.pending = true; + vmx->rmode.irq.vector = NMI_VECTOR; + vmx->rmode.irq.rip = kvm_rip_read(vcpu); + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + NMI_VECTOR | INTR_TYPE_SOFT_INTR | + INTR_INFO_VALID_MASK); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); + kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); return; } vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, @@ -3301,7 +3346,6 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu) static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu) { - kvm_make_request(KVM_REQ_EVENT, vcpu); return 1; } @@ -3314,8 +3358,6 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu) cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); - kvm_make_request(KVM_REQ_EVENT, vcpu); - ++vcpu->stat.irq_window_exits; /* @@ -3572,7 +3614,6 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu) cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); ++vcpu->stat.nmi_window_exits; - kvm_make_request(KVM_REQ_EVENT, vcpu); return 1; } @@ -3582,17 +3623,8 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); enum emulation_result err = EMULATE_DONE; int ret = 1; - u32 cpu_exec_ctrl; - bool intr_window_requested; - - cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); - intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING; while (!guest_state_valid(vcpu)) { - if (intr_window_requested - && (kvm_get_rflags(&vmx->vcpu) & X86_EFLAGS_IF)) - return handle_interrupt_window(&vmx->vcpu); - err = emulate_instruction(vcpu, 0, 0, 0); if (err == EMULATE_DO_MMIO) { @@ -3758,9 +3790,18 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) vmcs_write32(TPR_THRESHOLD, irr); } -static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) +static void vmx_complete_interrupts(struct vcpu_vmx *vmx) { - u32 exit_intr_info = vmx->exit_intr_info; + u32 exit_intr_info; + u32 idt_vectoring_info = vmx->idt_vectoring_info; + bool unblock_nmi; + u8 vector; + int type; + bool idtv_info_valid; + + exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); /* Handle machine checks before interrupts are enabled */ if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY) @@ -3775,16 +3816,8 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) asm("int $2"); kvm_after_handle_nmi(&vmx->vcpu); } -} -static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) -{ - u32 exit_intr_info = vmx->exit_intr_info; - bool unblock_nmi; - u8 vector; - bool idtv_info_valid; - - idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK; + idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; if (cpu_has_virtual_nmis()) { unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; @@ -3806,18 +3839,6 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) } else if (unlikely(vmx->soft_vnmi_blocked)) vmx->vnmi_blocked_time += ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time)); -} - -static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, - u32 idt_vectoring_info, - int instr_len_field, - int error_code_field) -{ - u8 vector; - int type; - bool idtv_info_valid; - - idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; vmx->vcpu.arch.nmi_injected = false; kvm_clear_exception_queue(&vmx->vcpu); @@ -3826,8 +3847,6 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, if (!idtv_info_valid) return; - kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu); - vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; @@ -3844,18 +3863,18 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, break; case INTR_TYPE_SOFT_EXCEPTION: vmx->vcpu.arch.event_exit_inst_len = - vmcs_read32(instr_len_field); + vmcs_read32(VM_EXIT_INSTRUCTION_LEN); /* fall through */ case INTR_TYPE_HARD_EXCEPTION: if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { - u32 err = vmcs_read32(error_code_field); + u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE); kvm_queue_exception_e(&vmx->vcpu, vector, err); } else kvm_queue_exception(&vmx->vcpu, vector); break; case INTR_TYPE_SOFT_INTR: vmx->vcpu.arch.event_exit_inst_len = - vmcs_read32(instr_len_field); + vmcs_read32(VM_EXIT_INSTRUCTION_LEN); /* fall through */ case INTR_TYPE_EXT_INTR: kvm_queue_interrupt(&vmx->vcpu, vector, @@ -3866,21 +3885,27 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, } } -static void vmx_complete_interrupts(struct vcpu_vmx *vmx) -{ - __vmx_complete_interrupts(vmx, vmx->idt_vectoring_info, - VM_EXIT_INSTRUCTION_LEN, - IDT_VECTORING_ERROR_CODE); -} - -static void vmx_cancel_injection(struct kvm_vcpu *vcpu) +/* + * Failure to inject an interrupt should give us the information + * in IDT_VECTORING_INFO_FIELD. However, if the failure occurs + * when fetching the interrupt redirection bitmap in the real-mode + * tss, this doesn't happen. So we do it ourselves. + */ +static void fixup_rmode_irq(struct vcpu_vmx *vmx) { - __vmx_complete_interrupts(to_vmx(vcpu), - vmcs_read32(VM_ENTRY_INTR_INFO_FIELD), - VM_ENTRY_INSTRUCTION_LEN, - VM_ENTRY_EXCEPTION_ERROR_CODE); - - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); + vmx->rmode.irq.pending = 0; + if (kvm_rip_read(&vmx->vcpu) + 1 != vmx->rmode.irq.rip) + return; + kvm_rip_write(&vmx->vcpu, vmx->rmode.irq.rip); + if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) { + vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK; + vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR; + return; + } + vmx->idt_vectoring_info = + VECTORING_INFO_VALID_MASK + | INTR_TYPE_EXT_INTR + | vmx->rmode.irq.vector; } #ifdef CONFIG_X86_64 @@ -4007,7 +4032,7 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) #endif [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)) : "cc", "memory" - , R"ax", R"bx", R"di", R"si" + , R"bx", R"di", R"si" #ifdef CONFIG_X86_64 , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" #endif @@ -4018,15 +4043,12 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) vcpu->arch.regs_dirty = 0; vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (vmx->rmode.irq.pending) + fixup_rmode_irq(vmx); asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); vmx->launched = 1; - vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); - vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - - vmx_complete_atomic_exit(vmx); - vmx_recover_nmi_blocking(vmx); vmx_complete_interrupts(vmx); } @@ -4097,7 +4119,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) cpu = get_cpu(); vmx_vcpu_load(&vmx->vcpu, cpu); - vmx->vcpu.cpu = cpu; err = vmx_vcpu_setup(vmx); vmx_vcpu_put(&vmx->vcpu); put_cpu(); @@ -4313,7 +4334,6 @@ static struct kvm_x86_ops vmx_x86_ops = { .set_irq = vmx_inject_irq, .set_nmi = vmx_inject_nmi, .queue_exception = vmx_queue_exception, - .cancel_injection = vmx_cancel_injection, .interrupt_allowed = vmx_interrupt_allowed, .nmi_allowed = vmx_nmi_allowed, .get_nmi_mask = vmx_get_nmi_mask, @@ -4336,11 +4356,6 @@ static struct kvm_x86_ops vmx_x86_ops = { .set_supported_cpuid = vmx_set_supported_cpuid, .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit, - - .write_tsc_offset = vmx_write_tsc_offset, - .adjust_tsc_offset = vmx_adjust_tsc_offset, - - .set_tdp_cr3 = vmx_set_cr3, }; static int __init vmx_init(void) diff --git a/trunk/arch/x86/kvm/x86.c b/trunk/arch/x86/kvm/x86.c index 2288ad829b32..6c2ecf0a806d 100644 --- a/trunk/arch/x86/kvm/x86.c +++ b/trunk/arch/x86/kvm/x86.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Qumranet, Inc. * Copyright (C) 2008 Qumranet, Inc. * Copyright IBM Corporation, 2008 - * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright 2010 Red Hat, Inc. and/or its affilates. * * Authors: * Avi Kivity @@ -55,8 +55,6 @@ #include #include #include -#include -#include #define MAX_IO_MSRS 256 #define CR0_RESERVED_BITS \ @@ -73,7 +71,7 @@ #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) #define KVM_MAX_MCE_BANKS 32 -#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P) +#define KVM_MCE_CAP_SUPPORTED MCG_CTL_P /* EFER defaults: * - enable syscall per default because its emulated by KVM @@ -284,8 +282,6 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, u32 prev_nr; int class1, class2; - kvm_make_request(KVM_REQ_EVENT, vcpu); - if (!vcpu->arch.exception.pending) { queue: vcpu->arch.exception.pending = true; @@ -331,28 +327,16 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr) } EXPORT_SYMBOL_GPL(kvm_requeue_exception); -void kvm_inject_page_fault(struct kvm_vcpu *vcpu) +void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, + u32 error_code) { - unsigned error_code = vcpu->arch.fault.error_code; - ++vcpu->stat.pf_guest; - vcpu->arch.cr2 = vcpu->arch.fault.address; + vcpu->arch.cr2 = addr; kvm_queue_exception_e(vcpu, PF_VECTOR, error_code); } -void kvm_propagate_fault(struct kvm_vcpu *vcpu) -{ - if (mmu_is_nested(vcpu) && !vcpu->arch.fault.nested) - vcpu->arch.nested_mmu.inject_page_fault(vcpu); - else - vcpu->arch.mmu.inject_page_fault(vcpu); - - vcpu->arch.fault.nested = false; -} - void kvm_inject_nmi(struct kvm_vcpu *vcpu) { - kvm_make_request(KVM_REQ_EVENT, vcpu); vcpu->arch.nmi_pending = 1; } EXPORT_SYMBOL_GPL(kvm_inject_nmi); @@ -382,50 +366,19 @@ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl) } EXPORT_SYMBOL_GPL(kvm_require_cpl); -/* - * This function will be used to read from the physical memory of the currently - * running guest. The difference to kvm_read_guest_page is that this function - * can read from guest physical or from the guest's guest physical memory. - */ -int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gfn_t ngfn, void *data, int offset, int len, - u32 access) -{ - gfn_t real_gfn; - gpa_t ngpa; - - ngpa = gfn_to_gpa(ngfn); - real_gfn = mmu->translate_gpa(vcpu, ngpa, access); - if (real_gfn == UNMAPPED_GVA) - return -EFAULT; - - real_gfn = gpa_to_gfn(real_gfn); - - return kvm_read_guest_page(vcpu->kvm, real_gfn, data, offset, len); -} -EXPORT_SYMBOL_GPL(kvm_read_guest_page_mmu); - -int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, - void *data, int offset, int len, u32 access) -{ - return kvm_read_guest_page_mmu(vcpu, vcpu->arch.walk_mmu, gfn, - data, offset, len, access); -} - /* * Load the pae pdptrs. Return true is they are all valid. */ -int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) +int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) { gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; int i; int ret; - u64 pdpte[ARRAY_SIZE(mmu->pdptrs)]; + u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; - ret = kvm_read_guest_page_mmu(vcpu, mmu, pdpt_gfn, pdpte, - offset * sizeof(u64), sizeof(pdpte), - PFERR_USER_MASK|PFERR_WRITE_MASK); + ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, + offset * sizeof(u64), sizeof(pdpte)); if (ret < 0) { ret = 0; goto out; @@ -439,7 +392,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) } ret = 1; - memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs)); + memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); __set_bit(VCPU_EXREG_PDPTR, (unsigned long *)&vcpu->arch.regs_avail); __set_bit(VCPU_EXREG_PDPTR, @@ -452,10 +405,8 @@ EXPORT_SYMBOL_GPL(load_pdptrs); static bool pdptrs_changed(struct kvm_vcpu *vcpu) { - u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)]; + u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; bool changed = true; - int offset; - gfn_t gfn; int r; if (is_long_mode(vcpu) || !is_pae(vcpu)) @@ -465,13 +416,10 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu) (unsigned long *)&vcpu->arch.regs_avail)) return true; - gfn = (vcpu->arch.cr3 & ~31u) >> PAGE_SHIFT; - offset = (vcpu->arch.cr3 & ~31u) & (PAGE_SIZE - 1); - r = kvm_read_nested_guest_page(vcpu, gfn, pdpte, offset, sizeof(pdpte), - PFERR_USER_MASK | PFERR_WRITE_MASK); + r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); if (r < 0) goto out; - changed = memcmp(pdpte, vcpu->arch.walk_mmu->pdptrs, sizeof(pdpte)) != 0; + changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; out: return changed; @@ -510,8 +458,7 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) return 1; } else #endif - if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, - vcpu->arch.cr3)) + if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) return 1; } @@ -600,7 +547,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 1; } else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE) && ((cr4 ^ old_cr4) & pdptr_bits) - && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3)) + && !load_pdptrs(vcpu, vcpu->arch.cr3)) return 1; if (cr4 & X86_CR4_VMXE) @@ -633,8 +580,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) if (is_pae(vcpu)) { if (cr3 & CR3_PAE_RESERVED_BITS) return 1; - if (is_paging(vcpu) && - !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) + if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) return 1; } /* @@ -791,7 +737,7 @@ static u32 msrs_to_save[] = { #ifdef CONFIG_X86_64 MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, #endif - MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA + MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA }; static unsigned num_msrs_to_save; @@ -892,7 +838,7 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock) /* * The guest calculates current wall clock time by adding - * system time (updated by kvm_guest_time_update below) to the + * system time (updated by kvm_write_guest_time below) to the * wall clock specified here. guest system time equals host * system time for us, thus we must fill in host boot time here. */ @@ -920,229 +866,65 @@ static uint32_t div_frac(uint32_t dividend, uint32_t divisor) return quotient; } -static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz, - s8 *pshift, u32 *pmultiplier) +static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock) { - uint64_t scaled64; + uint64_t nsecs = 1000000000LL; int32_t shift = 0; uint64_t tps64; uint32_t tps32; - tps64 = base_khz * 1000LL; - scaled64 = scaled_khz * 1000LL; - while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) { + tps64 = tsc_khz * 1000LL; + while (tps64 > nsecs*2) { tps64 >>= 1; shift--; } tps32 = (uint32_t)tps64; - while (tps32 <= scaled64 || scaled64 & 0xffffffff00000000ULL) { - if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000) - scaled64 >>= 1; - else - tps32 <<= 1; + while (tps32 <= (uint32_t)nsecs) { + tps32 <<= 1; shift++; } - *pshift = shift; - *pmultiplier = div_frac(scaled64, tps32); + hv_clock->tsc_shift = shift; + hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32); - pr_debug("%s: base_khz %u => %u, shift %d, mul %u\n", - __func__, base_khz, scaled_khz, shift, *pmultiplier); -} - -static inline u64 get_kernel_ns(void) -{ - struct timespec ts; - - WARN_ON(preemptible()); - ktime_get_ts(&ts); - monotonic_to_bootbased(&ts); - return timespec_to_ns(&ts); + pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n", + __func__, tsc_khz, hv_clock->tsc_shift, + hv_clock->tsc_to_system_mul); } static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz); -unsigned long max_tsc_khz; - -static inline int kvm_tsc_changes_freq(void) -{ - int cpu = get_cpu(); - int ret = !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && - cpufreq_quick_get(cpu) != 0; - put_cpu(); - return ret; -} -static inline u64 nsec_to_cycles(u64 nsec) -{ - u64 ret; - - WARN_ON(preemptible()); - if (kvm_tsc_changes_freq()) - printk_once(KERN_WARNING - "kvm: unreliable cycle conversion on adjustable rate TSC\n"); - ret = nsec * __get_cpu_var(cpu_tsc_khz); - do_div(ret, USEC_PER_SEC); - return ret; -} - -static void kvm_arch_set_tsc_khz(struct kvm *kvm, u32 this_tsc_khz) -{ - /* Compute a scale to convert nanoseconds in TSC cycles */ - kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000, - &kvm->arch.virtual_tsc_shift, - &kvm->arch.virtual_tsc_mult); - kvm->arch.virtual_tsc_khz = this_tsc_khz; -} - -static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) -{ - u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec, - vcpu->kvm->arch.virtual_tsc_mult, - vcpu->kvm->arch.virtual_tsc_shift); - tsc += vcpu->arch.last_tsc_write; - return tsc; -} - -void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data) -{ - struct kvm *kvm = vcpu->kvm; - u64 offset, ns, elapsed; - unsigned long flags; - s64 sdiff; - - spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); - offset = data - native_read_tsc(); - ns = get_kernel_ns(); - elapsed = ns - kvm->arch.last_tsc_nsec; - sdiff = data - kvm->arch.last_tsc_write; - if (sdiff < 0) - sdiff = -sdiff; - - /* - * Special case: close write to TSC within 5 seconds of - * another CPU is interpreted as an attempt to synchronize - * The 5 seconds is to accomodate host load / swapping as - * well as any reset of TSC during the boot process. - * - * In that case, for a reliable TSC, we can match TSC offsets, - * or make a best guest using elapsed value. - */ - if (sdiff < nsec_to_cycles(5ULL * NSEC_PER_SEC) && - elapsed < 5ULL * NSEC_PER_SEC) { - if (!check_tsc_unstable()) { - offset = kvm->arch.last_tsc_offset; - pr_debug("kvm: matched tsc offset for %llu\n", data); - } else { - u64 delta = nsec_to_cycles(elapsed); - offset += delta; - pr_debug("kvm: adjusted tsc offset by %llu\n", delta); - } - ns = kvm->arch.last_tsc_nsec; - } - kvm->arch.last_tsc_nsec = ns; - kvm->arch.last_tsc_write = data; - kvm->arch.last_tsc_offset = offset; - kvm_x86_ops->write_tsc_offset(vcpu, offset); - spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); - - /* Reset of TSC must disable overshoot protection below */ - vcpu->arch.hv_clock.tsc_timestamp = 0; - vcpu->arch.last_tsc_write = data; - vcpu->arch.last_tsc_nsec = ns; -} -EXPORT_SYMBOL_GPL(kvm_write_tsc); - -static int kvm_guest_time_update(struct kvm_vcpu *v) +static void kvm_write_guest_time(struct kvm_vcpu *v) { + struct timespec ts; unsigned long flags; struct kvm_vcpu_arch *vcpu = &v->arch; void *shared_kaddr; unsigned long this_tsc_khz; - s64 kernel_ns, max_kernel_ns; - u64 tsc_timestamp; - /* Keep irq disabled to prevent changes to the clock */ - local_irq_save(flags); - kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp); - kernel_ns = get_kernel_ns(); - this_tsc_khz = __get_cpu_var(cpu_tsc_khz); - - if (unlikely(this_tsc_khz == 0)) { - local_irq_restore(flags); - kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); - return 1; - } + if ((!vcpu->time_page)) + return; - /* - * We may have to catch up the TSC to match elapsed wall clock - * time for two reasons, even if kvmclock is used. - * 1) CPU could have been running below the maximum TSC rate - * 2) Broken TSC compensation resets the base at each VCPU - * entry to avoid unknown leaps of TSC even when running - * again on the same CPU. This may cause apparent elapsed - * time to disappear, and the guest to stand still or run - * very slowly. - */ - if (vcpu->tsc_catchup) { - u64 tsc = compute_guest_tsc(v, kernel_ns); - if (tsc > tsc_timestamp) { - kvm_x86_ops->adjust_tsc_offset(v, tsc - tsc_timestamp); - tsc_timestamp = tsc; - } + this_tsc_khz = get_cpu_var(cpu_tsc_khz); + if (unlikely(vcpu->hv_clock_tsc_khz != this_tsc_khz)) { + kvm_set_time_scale(this_tsc_khz, &vcpu->hv_clock); + vcpu->hv_clock_tsc_khz = this_tsc_khz; } + put_cpu_var(cpu_tsc_khz); + /* Keep irq disabled to prevent changes to the clock */ + local_irq_save(flags); + kvm_get_msr(v, MSR_IA32_TSC, &vcpu->hv_clock.tsc_timestamp); + ktime_get_ts(&ts); + monotonic_to_bootbased(&ts); local_irq_restore(flags); - if (!vcpu->time_page) - return 0; - - /* - * Time as measured by the TSC may go backwards when resetting the base - * tsc_timestamp. The reason for this is that the TSC resolution is - * higher than the resolution of the other clock scales. Thus, many - * possible measurments of the TSC correspond to one measurement of any - * other clock, and so a spread of values is possible. This is not a - * problem for the computation of the nanosecond clock; with TSC rates - * around 1GHZ, there can only be a few cycles which correspond to one - * nanosecond value, and any path through this code will inevitably - * take longer than that. However, with the kernel_ns value itself, - * the precision may be much lower, down to HZ granularity. If the - * first sampling of TSC against kernel_ns ends in the low part of the - * range, and the second in the high end of the range, we can get: - * - * (TSC - offset_low) * S + kns_old > (TSC - offset_high) * S + kns_new - * - * As the sampling errors potentially range in the thousands of cycles, - * it is possible such a time value has already been observed by the - * guest. To protect against this, we must compute the system time as - * observed by the guest and ensure the new system time is greater. - */ - max_kernel_ns = 0; - if (vcpu->hv_clock.tsc_timestamp && vcpu->last_guest_tsc) { - max_kernel_ns = vcpu->last_guest_tsc - - vcpu->hv_clock.tsc_timestamp; - max_kernel_ns = pvclock_scale_delta(max_kernel_ns, - vcpu->hv_clock.tsc_to_system_mul, - vcpu->hv_clock.tsc_shift); - max_kernel_ns += vcpu->last_kernel_ns; - } - - if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) { - kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz, - &vcpu->hv_clock.tsc_shift, - &vcpu->hv_clock.tsc_to_system_mul); - vcpu->hw_tsc_khz = this_tsc_khz; - } + /* With all the info we got, fill in the values */ - if (max_kernel_ns > kernel_ns) - kernel_ns = max_kernel_ns; + vcpu->hv_clock.system_time = ts.tv_nsec + + (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset; - /* With all the info we got, fill in the values */ - vcpu->hv_clock.tsc_timestamp = tsc_timestamp; - vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset; - vcpu->last_kernel_ns = kernel_ns; - vcpu->last_guest_tsc = tsc_timestamp; vcpu->hv_clock.flags = 0; /* @@ -1160,7 +942,16 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) kunmap_atomic(shared_kaddr, KM_USER0); mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); - return 0; +} + +static int kvm_request_guest_time_update(struct kvm_vcpu *v) +{ + struct kvm_vcpu_arch *vcpu = &v->arch; + + if (!vcpu->time_page) + return 0; + kvm_make_request(KVM_REQ_KVMCLOCK_UPDATE, v); + return 1; } static bool msr_mtrr_valid(unsigned msr) @@ -1486,7 +1277,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) } vcpu->arch.time = data; - kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); /* we verify if the enable bit is set... */ if (!(data & 1)) @@ -1502,6 +1292,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) kvm_release_page_clean(vcpu->arch.time_page); vcpu->arch.time_page = NULL; } + + kvm_request_guest_time_update(vcpu); break; } case MSR_IA32_MCG_CTL: @@ -1538,16 +1330,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) pr_unimpl(vcpu, "unimplemented perfctr wrmsr: " "0x%x data 0x%llx\n", msr, data); break; - case MSR_K7_CLK_CTL: - /* - * Ignore all writes to this no longer documented MSR. - * Writes are only relevant for old K7 processors, - * all pre-dating SVM, but a recommended workaround from - * AMD for these chips. It is possible to speicify the - * affected processor models on the command line, hence - * the need to ignore the workaround. - */ - break; case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15: if (kvm_hv_msr_partition_wide(msr)) { int r; @@ -1740,20 +1522,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case 0xcd: /* fsb frequency */ data = 3; break; - /* - * MSR_EBC_FREQUENCY_ID - * Conservative value valid for even the basic CPU models. - * Models 0,1: 000 in bits 23:21 indicating a bus speed of - * 100MHz, model 2 000 in bits 18:16 indicating 100MHz, - * and 266MHz for model 3, or 4. Set Core Clock - * Frequency to System Bus Frequency Ratio to 1 (bits - * 31:24) even though these are only valid for CPU - * models > 2, however guests may end up dividing or - * multiplying by zero otherwise. - */ - case MSR_EBC_FREQUENCY_ID: - data = 1 << 24; - break; case MSR_IA32_APICBASE: data = kvm_get_apic_base(vcpu); break; @@ -1787,18 +1555,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_IA32_MCG_STATUS: case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1: return get_msr_mce(vcpu, msr, pdata); - case MSR_K7_CLK_CTL: - /* - * Provide expected ramp-up count for K7. All other - * are set to zero, indicating minimum divisors for - * every field. - * - * This prevents guest kernels on AMD host with CPU - * type 6, model 8 and higher from exploding due to - * the rdmsr failing. - */ - data = 0x20000000; - break; case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15: if (kvm_hv_msr_partition_wide(msr)) { int r; @@ -2052,28 +1808,19 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } kvm_x86_ops->vcpu_load(vcpu, cpu); - if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) { - /* Make sure TSC doesn't go backwards */ - s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 : - native_read_tsc() - vcpu->arch.last_host_tsc; - if (tsc_delta < 0) - mark_tsc_unstable("KVM discovered backwards TSC"); - if (check_tsc_unstable()) { - kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta); - vcpu->arch.tsc_catchup = 1; - kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); - } - if (vcpu->cpu != cpu) - kvm_migrate_timers(vcpu); - vcpu->cpu = cpu; + if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) { + unsigned long khz = cpufreq_quick_get(cpu); + if (!khz) + khz = tsc_khz; + per_cpu(cpu_tsc_khz, cpu) = khz; } + kvm_request_guest_time_update(vcpu); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { kvm_x86_ops->vcpu_put(vcpu); kvm_put_guest_fpu(vcpu); - vcpu->arch.last_host_tsc = native_read_tsc(); } static int is_efer_nx(void) @@ -2248,7 +1995,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, F(F16C); /* cpuid 0x80000001.ecx */ const u32 kvm_supported_word6_x86_features = - F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ | + F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ | F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) | F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) | 0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM); @@ -2457,7 +2204,6 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, return -ENXIO; kvm_queue_interrupt(vcpu, irq->irq, false); - kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; } @@ -2611,8 +2357,6 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR) vcpu->arch.sipi_vector = events->sipi_vector; - kvm_make_request(KVM_REQ_EVENT, vcpu); - return 0; } @@ -3016,7 +2760,7 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) { - return kvm->arch.n_max_mmu_pages; + return kvm->arch.n_alloc_mmu_pages; } static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) @@ -3052,18 +2796,18 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) r = 0; switch (chip->chip_id) { case KVM_IRQCHIP_PIC_MASTER: - spin_lock(&pic_irqchip(kvm)->lock); + raw_spin_lock(&pic_irqchip(kvm)->lock); memcpy(&pic_irqchip(kvm)->pics[0], &chip->chip.pic, sizeof(struct kvm_pic_state)); - spin_unlock(&pic_irqchip(kvm)->lock); + raw_spin_unlock(&pic_irqchip(kvm)->lock); break; case KVM_IRQCHIP_PIC_SLAVE: - spin_lock(&pic_irqchip(kvm)->lock); + raw_spin_lock(&pic_irqchip(kvm)->lock); memcpy(&pic_irqchip(kvm)->pics[1], &chip->chip.pic, sizeof(struct kvm_pic_state)); - spin_unlock(&pic_irqchip(kvm)->lock); + raw_spin_unlock(&pic_irqchip(kvm)->lock); break; case KVM_IRQCHIP_IOAPIC: r = kvm_set_ioapic(kvm, &chip->chip.ioapic); @@ -3457,6 +3201,7 @@ long kvm_arch_vm_ioctl(struct file *filp, break; } case KVM_SET_CLOCK: { + struct timespec now; struct kvm_clock_data user_ns; u64 now_ns; s64 delta; @@ -3470,21 +3215,20 @@ long kvm_arch_vm_ioctl(struct file *filp, goto out; r = 0; - local_irq_disable(); - now_ns = get_kernel_ns(); + ktime_get_ts(&now); + now_ns = timespec_to_ns(&now); delta = user_ns.clock - now_ns; - local_irq_enable(); kvm->arch.kvmclock_offset = delta; break; } case KVM_GET_CLOCK: { + struct timespec now; struct kvm_clock_data user_ns; u64 now_ns; - local_irq_disable(); - now_ns = get_kernel_ns(); + ktime_get_ts(&now); + now_ns = timespec_to_ns(&now); user_ns.clock = kvm->arch.kvmclock_offset + now_ns; - local_irq_enable(); user_ns.flags = 0; r = -EFAULT; @@ -3548,51 +3292,30 @@ void kvm_get_segment(struct kvm_vcpu *vcpu, kvm_x86_ops->get_segment(vcpu, var, seg); } -static gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access) -{ - return gpa; -} - -static gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access) -{ - gpa_t t_gpa; - u32 error; - - BUG_ON(!mmu_is_nested(vcpu)); - - /* NPT walks are always user-walks */ - access |= PFERR_USER_MASK; - t_gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gpa, access, &error); - if (t_gpa == UNMAPPED_GVA) - vcpu->arch.fault.nested = true; - - return t_gpa; -} - gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) { u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; - return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error); + return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error); } gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) { u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; access |= PFERR_FETCH_MASK; - return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error); + return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error); } gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) { u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; access |= PFERR_WRITE_MASK; - return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error); + return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error); } /* uses this to access any guest's mapped memory without checking CPL */ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) { - return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, 0, error); + return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, 0, error); } static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, @@ -3603,8 +3326,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, int r = X86EMUL_CONTINUE; while (bytes) { - gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, access, - error); + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error); unsigned offset = addr & (PAGE_SIZE-1); unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -3659,9 +3381,8 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val, int r = X86EMUL_CONTINUE; while (bytes) { - gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, - PFERR_WRITE_MASK, - error); + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, + PFERR_WRITE_MASK, error); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -3903,7 +3624,7 @@ static int emulator_pio_in_emulated(int size, unsigned short port, void *val, if (vcpu->arch.pio.count) goto data_avail; - trace_kvm_pio(0, port, size, 1); + trace_kvm_pio(1, port, size, 1); vcpu->arch.pio.port = port; vcpu->arch.pio.in = 1; @@ -3931,7 +3652,7 @@ static int emulator_pio_out_emulated(int size, unsigned short port, const void *val, unsigned int count, struct kvm_vcpu *vcpu) { - trace_kvm_pio(1, port, size, 1); + trace_kvm_pio(0, port, size, 1); vcpu->arch.pio.port = port; vcpu->arch.pio.in = 0; @@ -4070,11 +3791,6 @@ static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu) kvm_x86_ops->get_gdt(vcpu, dt); } -static void emulator_get_idt(struct desc_ptr *dt, struct kvm_vcpu *vcpu) -{ - kvm_x86_ops->get_idt(vcpu, dt); -} - static unsigned long emulator_get_cached_segment_base(int seg, struct kvm_vcpu *vcpu) { @@ -4168,7 +3884,6 @@ static struct x86_emulate_ops emulate_ops = { .set_segment_selector = emulator_set_segment_selector, .get_cached_segment_base = emulator_get_cached_segment_base, .get_gdt = emulator_get_gdt, - .get_idt = emulator_get_idt, .get_cr = emulator_get_cr, .set_cr = emulator_set_cr, .cpl = emulator_get_cpl, @@ -4204,64 +3919,13 @@ static void inject_emulated_exception(struct kvm_vcpu *vcpu) { struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; if (ctxt->exception == PF_VECTOR) - kvm_propagate_fault(vcpu); + kvm_inject_page_fault(vcpu, ctxt->cr2, ctxt->error_code); else if (ctxt->error_code_valid) kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code); else kvm_queue_exception(vcpu, ctxt->exception); } -static void init_emulate_ctxt(struct kvm_vcpu *vcpu) -{ - struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; - int cs_db, cs_l; - - cache_all_regs(vcpu); - - kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); - - vcpu->arch.emulate_ctxt.vcpu = vcpu; - vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); - vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu); - vcpu->arch.emulate_ctxt.mode = - (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : - (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM) - ? X86EMUL_MODE_VM86 : cs_l - ? X86EMUL_MODE_PROT64 : cs_db - ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; - memset(c, 0, sizeof(struct decode_cache)); - memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); -} - -int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq) -{ - struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; - int ret; - - init_emulate_ctxt(vcpu); - - vcpu->arch.emulate_ctxt.decode.op_bytes = 2; - vcpu->arch.emulate_ctxt.decode.ad_bytes = 2; - vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip; - ret = emulate_int_real(&vcpu->arch.emulate_ctxt, &emulate_ops, irq); - - if (ret != X86EMUL_CONTINUE) - return EMULATE_FAIL; - - vcpu->arch.emulate_ctxt.eip = c->eip; - memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); - kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); - kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); - - if (irq == NMI_VECTOR) - vcpu->arch.nmi_pending = false; - else - vcpu->arch.interrupt.pending = false; - - return EMULATE_DONE; -} -EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt); - static int handle_emulation_failure(struct kvm_vcpu *vcpu) { ++vcpu->stat.insn_emulation_fail; @@ -4318,15 +3982,24 @@ int emulate_instruction(struct kvm_vcpu *vcpu, cache_all_regs(vcpu); if (!(emulation_type & EMULTYPE_NO_DECODE)) { - init_emulate_ctxt(vcpu); + int cs_db, cs_l; + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); + + vcpu->arch.emulate_ctxt.vcpu = vcpu; + vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); + vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu); + vcpu->arch.emulate_ctxt.mode = + (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : + (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM) + ? X86EMUL_MODE_VM86 : cs_l + ? X86EMUL_MODE_PROT64 : cs_db + ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + memset(c, 0, sizeof(struct decode_cache)); + memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); vcpu->arch.emulate_ctxt.interruptibility = 0; vcpu->arch.emulate_ctxt.exception = -1; - vcpu->arch.emulate_ctxt.perm_ok = false; - - r = x86_decode_insn(&vcpu->arch.emulate_ctxt); - if (r == X86EMUL_PROPAGATE_FAULT) - goto done; + r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); trace_kvm_emulate_insn_start(vcpu); /* Only allow emulation of specific instructions on #UD @@ -4376,39 +4049,41 @@ int emulate_instruction(struct kvm_vcpu *vcpu, memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); restart: - r = x86_emulate_insn(&vcpu->arch.emulate_ctxt); + r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); - if (r == EMULATION_FAILED) { + if (r) { /* emulation failed */ if (reexecute_instruction(vcpu, cr2)) return EMULATE_DONE; return handle_emulation_failure(vcpu); } -done: + toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility); + kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); + memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); + if (vcpu->arch.emulate_ctxt.exception >= 0) { inject_emulated_exception(vcpu); - r = EMULATE_DONE; - } else if (vcpu->arch.pio.count) { + return EMULATE_DONE; + } + + if (vcpu->arch.pio.count) { if (!vcpu->arch.pio.in) vcpu->arch.pio.count = 0; - r = EMULATE_DO_MMIO; - } else if (vcpu->mmio_needed) { + return EMULATE_DO_MMIO; + } + + if (vcpu->mmio_needed) { if (vcpu->mmio_is_write) vcpu->mmio_needed = 0; - r = EMULATE_DO_MMIO; - } else if (r == EMULATION_RESTART) - goto restart; - else - r = EMULATE_DONE; + return EMULATE_DO_MMIO; + } - toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility); - kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); - kvm_make_request(KVM_REQ_EVENT, vcpu); - memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); - kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); + if (vcpu->arch.emulate_ctxt.restart) + goto restart; - return r; + return EMULATE_DONE; } EXPORT_SYMBOL_GPL(emulate_instruction); @@ -4422,23 +4097,9 @@ int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port) } EXPORT_SYMBOL_GPL(kvm_fast_pio_out); -static void tsc_bad(void *info) -{ - __get_cpu_var(cpu_tsc_khz) = 0; -} - -static void tsc_khz_changed(void *data) +static void bounce_off(void *info) { - struct cpufreq_freqs *freq = data; - unsigned long khz = 0; - - if (data) - khz = freq->new; - else if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) - khz = cpufreq_quick_get(raw_smp_processor_id()); - if (!khz) - khz = tsc_khz; - __get_cpu_var(cpu_tsc_khz) = khz; + /* nothing */ } static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val, @@ -4449,60 +4110,21 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va struct kvm_vcpu *vcpu; int i, send_ipi = 0; - /* - * We allow guests to temporarily run on slowing clocks, - * provided we notify them after, or to run on accelerating - * clocks, provided we notify them before. Thus time never - * goes backwards. - * - * However, we have a problem. We can't atomically update - * the frequency of a given CPU from this function; it is - * merely a notifier, which can be called from any CPU. - * Changing the TSC frequency at arbitrary points in time - * requires a recomputation of local variables related to - * the TSC for each VCPU. We must flag these local variables - * to be updated and be sure the update takes place with the - * new frequency before any guests proceed. - * - * Unfortunately, the combination of hotplug CPU and frequency - * change creates an intractable locking scenario; the order - * of when these callouts happen is undefined with respect to - * CPU hotplug, and they can race with each other. As such, - * merely setting per_cpu(cpu_tsc_khz) = X during a hotadd is - * undefined; you can actually have a CPU frequency change take - * place in between the computation of X and the setting of the - * variable. To protect against this problem, all updates of - * the per_cpu tsc_khz variable are done in an interrupt - * protected IPI, and all callers wishing to update the value - * must wait for a synchronous IPI to complete (which is trivial - * if the caller is on the CPU already). This establishes the - * necessary total order on variable updates. - * - * Note that because a guest time update may take place - * anytime after the setting of the VCPU's request bit, the - * correct TSC value must be set before the request. However, - * to ensure the update actually makes it to any guest which - * starts running in hardware virtualization between the set - * and the acquisition of the spinlock, we must also ping the - * CPU after setting the request bit. - * - */ - if (val == CPUFREQ_PRECHANGE && freq->old > freq->new) return 0; if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new) return 0; - - smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1); + per_cpu(cpu_tsc_khz, freq->cpu) = freq->new; spin_lock(&kvm_lock); list_for_each_entry(kvm, &vm_list, vm_list) { kvm_for_each_vcpu(i, vcpu, kvm) { if (vcpu->cpu != freq->cpu) continue; - kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); + if (!kvm_request_guest_time_update(vcpu)) + continue; if (vcpu->cpu != smp_processor_id()) - send_ipi = 1; + send_ipi++; } } spin_unlock(&kvm_lock); @@ -4520,57 +4142,32 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va * guest context is entered kvmclock will be updated, * so the guest will not see stale values. */ - smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1); + smp_call_function_single(freq->cpu, bounce_off, NULL, 1); } return 0; } static struct notifier_block kvmclock_cpufreq_notifier_block = { - .notifier_call = kvmclock_cpufreq_notifier -}; - -static int kvmclock_cpu_notifier(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_DOWN_FAILED: - smp_call_function_single(cpu, tsc_khz_changed, NULL, 1); - break; - case CPU_DOWN_PREPARE: - smp_call_function_single(cpu, tsc_bad, NULL, 1); - break; - } - return NOTIFY_OK; -} - -static struct notifier_block kvmclock_cpu_notifier_block = { - .notifier_call = kvmclock_cpu_notifier, - .priority = -INT_MAX + .notifier_call = kvmclock_cpufreq_notifier }; static void kvm_timer_init(void) { int cpu; - max_tsc_khz = tsc_khz; - register_hotcpu_notifier(&kvmclock_cpu_notifier_block); if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { -#ifdef CONFIG_CPU_FREQ - struct cpufreq_policy policy; - memset(&policy, 0, sizeof(policy)); - cpufreq_get_policy(&policy, get_cpu()); - if (policy.cpuinfo.max_freq) - max_tsc_khz = policy.cpuinfo.max_freq; -#endif cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + for_each_online_cpu(cpu) { + unsigned long khz = cpufreq_get(cpu); + if (!khz) + khz = tsc_khz; + per_cpu(cpu_tsc_khz, cpu) = khz; + } + } else { + for_each_possible_cpu(cpu) + per_cpu(cpu_tsc_khz, cpu) = tsc_khz; } - pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz); - for_each_online_cpu(cpu) - smp_call_function_single(cpu, tsc_khz_changed, NULL, 1); } static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); @@ -4672,7 +4269,6 @@ void kvm_arch_exit(void) if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); - unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block); kvm_x86_ops = NULL; kvm_mmu_module_exit(); } @@ -5088,11 +4684,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) kvm_mmu_unload(vcpu); if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu)) __kvm_migrate_timers(vcpu); - if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) { - r = kvm_guest_time_update(vcpu); - if (unlikely(r)) - goto out; - } + if (kvm_check_request(KVM_REQ_KVMCLOCK_UPDATE, vcpu)) + kvm_write_guest_time(vcpu); if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu)) kvm_mmu_sync_roots(vcpu); if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) @@ -5117,21 +4710,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (unlikely(r)) goto out; - if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) { - inject_pending_event(vcpu); - - /* enable NMI/IRQ window open exits if needed */ - if (vcpu->arch.nmi_pending) - kvm_x86_ops->enable_nmi_window(vcpu); - else if (kvm_cpu_has_interrupt(vcpu) || req_int_win) - kvm_x86_ops->enable_irq_window(vcpu); - - if (kvm_lapic_enabled(vcpu)) { - update_cr8_intercept(vcpu); - kvm_lapic_sync_to_vapic(vcpu); - } - } - preempt_disable(); kvm_x86_ops->prepare_guest_switch(vcpu); @@ -5150,11 +4728,23 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) smp_wmb(); local_irq_enable(); preempt_enable(); - kvm_x86_ops->cancel_injection(vcpu); r = 1; goto out; } + inject_pending_event(vcpu); + + /* enable NMI/IRQ window open exits if needed */ + if (vcpu->arch.nmi_pending) + kvm_x86_ops->enable_nmi_window(vcpu); + else if (kvm_cpu_has_interrupt(vcpu) || req_int_win) + kvm_x86_ops->enable_irq_window(vcpu); + + if (kvm_lapic_enabled(vcpu)) { + update_cr8_intercept(vcpu); + kvm_lapic_sync_to_vapic(vcpu); + } + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); kvm_guest_enter(); @@ -5180,8 +4770,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (hw_breakpoint_active()) hw_breakpoint_restore(); - kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc); - atomic_set(&vcpu->guest_mode, 0); smp_wmb(); local_irq_enable(); @@ -5311,7 +4899,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (!irqchip_in_kernel(vcpu->kvm)) kvm_set_cr8(vcpu, kvm_run->cr8); - if (vcpu->arch.pio.count || vcpu->mmio_needed) { + if (vcpu->arch.pio.count || vcpu->mmio_needed || + vcpu->arch.emulate_ctxt.restart) { if (vcpu->mmio_needed) { memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); vcpu->mmio_read_completed = 1; @@ -5392,8 +4981,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) vcpu->arch.exception.pending = false; - kvm_make_request(KVM_REQ_EVENT, vcpu); - return 0; } @@ -5457,7 +5044,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { vcpu->arch.mp_state = mp_state->mp_state; - kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; } @@ -5465,11 +5051,24 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, bool has_error_code, u32 error_code) { struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; - int ret; + int cs_db, cs_l, ret; + cache_all_regs(vcpu); + + kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); - init_emulate_ctxt(vcpu); + vcpu->arch.emulate_ctxt.vcpu = vcpu; + vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); + vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu); + vcpu->arch.emulate_ctxt.mode = + (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : + (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM) + ? X86EMUL_MODE_VM86 : cs_l + ? X86EMUL_MODE_PROT64 : cs_db + ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + memset(c, 0, sizeof(struct decode_cache)); + memcpy(c->regs, vcpu->arch.regs, sizeof c->regs); - ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, + ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops, tss_selector, reason, has_error_code, error_code); @@ -5479,7 +5078,6 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, memcpy(vcpu->arch.regs, c->regs, sizeof c->regs); kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip); kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); - kvm_make_request(KVM_REQ_EVENT, vcpu); return EMULATE_DONE; } EXPORT_SYMBOL_GPL(kvm_task_switch); @@ -5515,7 +5113,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; kvm_x86_ops->set_cr4(vcpu, sregs->cr4); if (!is_long_mode(vcpu) && is_pae(vcpu)) { - load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3); + load_pdptrs(vcpu, vcpu->arch.cr3); mmu_reset_needed = 1; } @@ -5550,8 +5148,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, !is_protmode(vcpu)) vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; - kvm_make_request(KVM_REQ_EVENT, vcpu); - return 0; } @@ -5738,10 +5334,6 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) { - if (check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0) - printk_once(KERN_WARNING - "kvm: SMP vm created on host with unstable TSC; " - "guest TSC will not be reliable\n"); return kvm_x86_ops->vcpu_create(kvm, id); } @@ -5784,22 +5376,22 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.dr6 = DR6_FIXED_1; vcpu->arch.dr7 = DR7_FIXED_1; - kvm_make_request(KVM_REQ_EVENT, vcpu); - return kvm_x86_ops->vcpu_reset(vcpu); } int kvm_arch_hardware_enable(void *garbage) { - struct kvm *kvm; - struct kvm_vcpu *vcpu; - int i; + /* + * Since this may be called from a hotplug notifcation, + * we can't get the CPU frequency directly. + */ + if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { + int cpu = raw_smp_processor_id(); + per_cpu(cpu_tsc_khz, cpu) = 0; + } kvm_shared_msr_cpu_online(); - list_for_each_entry(kvm, &vm_list, vm_list) - kvm_for_each_vcpu(i, vcpu, kvm) - if (vcpu->cpu == smp_processor_id()) - kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); + return kvm_x86_ops->hardware_enable(garbage); } @@ -5833,11 +5425,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) BUG_ON(vcpu->kvm == NULL); kvm = vcpu->kvm; - vcpu->arch.emulate_ctxt.ops = &emulate_ops; - vcpu->arch.walk_mmu = &vcpu->arch.mmu; vcpu->arch.mmu.root_hpa = INVALID_PAGE; - vcpu->arch.mmu.translate_gpa = translate_gpa; - vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa; if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu)) vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; else @@ -5850,9 +5438,6 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) } vcpu->arch.pio_data = page_address(page); - if (!kvm->arch.virtual_tsc_khz) - kvm_arch_set_tsc_khz(kvm, max_tsc_khz); - r = kvm_mmu_create(vcpu); if (r < 0) goto fail_free_pio_data; @@ -5912,7 +5497,7 @@ struct kvm *kvm_arch_create_vm(void) /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */ set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap); - spin_lock_init(&kvm->arch.tsc_write_lock); + rdtscll(kvm->arch.vm_init_tsc); return kvm; } @@ -6099,7 +5684,6 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip)) rflags |= X86_EFLAGS_TF; kvm_x86_ops->set_rflags(vcpu, rflags); - kvm_make_request(KVM_REQ_EVENT, vcpu); } EXPORT_SYMBOL_GPL(kvm_set_rflags); diff --git a/trunk/arch/x86/kvm/x86.h b/trunk/arch/x86/kvm/x86.h index 2cea414489f3..b7a404722d2b 100644 --- a/trunk/arch/x86/kvm/x86.h +++ b/trunk/arch/x86/kvm/x86.h @@ -50,11 +50,6 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu) #endif } -static inline bool mmu_is_nested(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu; -} - static inline int is_pae(struct kvm_vcpu *vcpu) { return kvm_read_cr4_bits(vcpu, X86_CR4_PAE); @@ -72,8 +67,5 @@ static inline int is_paging(struct kvm_vcpu *vcpu) void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); -int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq); - -void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data); #endif diff --git a/trunk/arch/xtensa/include/asm/uaccess.h b/trunk/arch/xtensa/include/asm/uaccess.h index 5b0c18c1cce1..b8528426ab1f 100644 --- a/trunk/arch/xtensa/include/asm/uaccess.h +++ b/trunk/arch/xtensa/include/asm/uaccess.h @@ -4,7 +4,7 @@ * User space memory access functions * * These routines provide basic accessing functions to the user memory - * space for the kernel. This header file provides functions such as: + * space for the kernel. This header file provides fuctions such as: * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index 881fe44ec7da..f8548876d7ea 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -64,15 +64,13 @@ static void drive_stat_acct(struct request *rq, int new_io) return; cpu = part_stat_lock(); + part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); - if (!new_io) { - part = rq->part; + if (!new_io) part_stat_inc(cpu, part, merges[rw]); - } else { - part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); + else { part_round_stats(cpu, part); part_inc_in_flight(part, rw); - rq->part = part; } part_stat_unlock(); @@ -130,7 +128,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq) rq->ref_count = 1; rq->start_time = jiffies; set_start_time_ns(rq); - rq->part = NULL; } EXPORT_SYMBOL(blk_rq_init); @@ -805,16 +802,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags, rl->starved[is_sync] = 0; priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); - if (priv) { + if (priv) rl->elvpriv++; - /* - * Don't do stats for non-priv requests - */ - if (blk_queue_io_stat(q)) - rw_flags |= REQ_IO_STAT; - } - + if (blk_queue_io_stat(q)) + rw_flags |= REQ_IO_STAT; spin_unlock_irq(q->queue_lock); rq = blk_alloc_request(q, rw_flags, priv, gfp_mask); @@ -1669,7 +1661,7 @@ EXPORT_SYMBOL(submit_bio); * the insertion using this generic function. * * This function should also be useful for request stacking drivers - * in some cases below, so export this function. + * in some cases below, so export this fuction. * Request stacking drivers like request-based dm may change the queue * limits while requests are in the queue (e.g. dm's table swapping). * Such request stacking drivers should check those requests agaist @@ -1791,7 +1783,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) int cpu; cpu = part_stat_lock(); - part = req->part; + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_add(cpu, part, sectors[rw], bytes >> 9); part_stat_unlock(); } @@ -1811,7 +1803,7 @@ static void blk_account_io_done(struct request *req) int cpu; cpu = part_stat_lock(); - part = req->part; + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_inc(cpu, part, ios[rw]); part_stat_add(cpu, part, ticks[rw], duration); diff --git a/trunk/block/blk-merge.c b/trunk/block/blk-merge.c index 0a2fd8a48a38..77b7c26df6b5 100644 --- a/trunk/block/blk-merge.c +++ b/trunk/block/blk-merge.c @@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req) int cpu; cpu = part_stat_lock(); - part = req->part; + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_round_stats(cpu, part); part_dec_in_flight(part, rq_data_dir(req)); diff --git a/trunk/block/blk.h b/trunk/block/blk.h index 1e675e5ade02..2db8f32838e7 100644 --- a/trunk/block/blk.h +++ b/trunk/block/blk.h @@ -116,6 +116,10 @@ void blk_queue_congestion_threshold(struct request_queue *q); int blk_dev_init(void); +void elv_quiesce_start(struct request_queue *q); +void elv_quiesce_end(struct request_queue *q); + + /* * Return the threshold (number of used requests) at which the queue is * considered to be congested. It include a little hysteresis to keep the diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index a8adf96a4b41..5fa2b44a72ff 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -929,15 +929,8 @@ static void disk_free_ptbl_rcu_cb(struct rcu_head *head) { struct disk_part_tbl *ptbl = container_of(head, struct disk_part_tbl, rcu_head); - struct gendisk *disk = ptbl->disk; - struct request_queue *q = disk->queue; - unsigned long flags; kfree(ptbl); - - spin_lock_irqsave(q->queue_lock, flags); - elv_quiesce_end(q); - spin_unlock_irqrestore(q->queue_lock, flags); } /** @@ -955,17 +948,11 @@ static void disk_replace_part_tbl(struct gendisk *disk, struct disk_part_tbl *new_ptbl) { struct disk_part_tbl *old_ptbl = disk->part_tbl; - struct request_queue *q = disk->queue; rcu_assign_pointer(disk->part_tbl, new_ptbl); if (old_ptbl) { rcu_assign_pointer(old_ptbl->last_lookup, NULL); - - spin_lock_irq(q->queue_lock); - elv_quiesce_start(q); - spin_unlock_irq(q->queue_lock); - call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb); } } @@ -1006,7 +993,6 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno) return -ENOMEM; new_ptbl->len = target; - new_ptbl->disk = disk; for (i = 0; i < len; i++) rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]); diff --git a/trunk/crypto/Kconfig b/trunk/crypto/Kconfig index e4bac29a32e7..e573077f1672 100644 --- a/trunk/crypto/Kconfig +++ b/trunk/crypto/Kconfig @@ -23,12 +23,13 @@ comment "Crypto core or helper" config CRYPTO_FIPS bool "FIPS 200 compliance" - depends on CRYPTO_ANSI_CPRNG && !CRYPTO_MANAGER_DISABLE_TESTS + depends on CRYPTO_ANSI_CPRNG help This options enables the fips boot option which is required if you want to system to operate in a FIPS 200 certification. You should say no unless you know what - this is. + this is. Note that CRYPTO_ANSI_CPRNG is required if this + option is selected config CRYPTO_ALGAPI tristate @@ -364,7 +365,7 @@ config CRYPTO_RMD128 RIPEMD-160 should be used. Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See + See config CRYPTO_RMD160 tristate "RIPEMD-160 digest algorithm" @@ -381,7 +382,7 @@ config CRYPTO_RMD160 against RIPEMD-160. Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See + See config CRYPTO_RMD256 tristate "RIPEMD-256 digest algorithm" @@ -393,7 +394,7 @@ config CRYPTO_RMD256 (than RIPEMD-128). Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See + See config CRYPTO_RMD320 tristate "RIPEMD-320 digest algorithm" @@ -405,7 +406,7 @@ config CRYPTO_RMD320 (than RIPEMD-160). Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See + See config CRYPTO_SHA1 tristate "SHA1 digest algorithm" @@ -460,7 +461,7 @@ config CRYPTO_WP512 Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard See also: - + config CRYPTO_GHASH_CLMUL_NI_INTEL tristate "GHASH digest algorithm (CLMUL-NI accelerated)" @@ -578,8 +579,8 @@ config CRYPTO_ANUBIS in the NESSIE competition. See also: - - + + config CRYPTO_ARC4 tristate "ARC4 cipher algorithm" @@ -658,7 +659,7 @@ config CRYPTO_KHAZAD on 32-bit processors. Khazad uses an 128 bit key size. See also: - + config CRYPTO_SALSA20 tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)" diff --git a/trunk/crypto/cryptd.c b/trunk/crypto/cryptd.c index e46d21ae26bc..ef71318976c7 100644 --- a/trunk/crypto/cryptd.c +++ b/trunk/crypto/cryptd.c @@ -3,13 +3,6 @@ * * Copyright (c) 2006 Herbert Xu * - * Added AEAD support to cryptd. - * Authors: Tadeusz Struk (tadeusz.struk@intel.com) - * Adrian Hoban - * Gabriele Paoloni - * Aidan O'Mahony (aidan.o.mahony@intel.com) - * Copyright (c) 2010, Intel Corporation. - * * 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) @@ -19,7 +12,6 @@ #include #include -#include #include #include #include @@ -52,11 +44,6 @@ struct hashd_instance_ctx { struct cryptd_queue *queue; }; -struct aead_instance_ctx { - struct crypto_aead_spawn aead_spawn; - struct cryptd_queue *queue; -}; - struct cryptd_blkcipher_ctx { struct crypto_blkcipher *child; }; @@ -74,14 +61,6 @@ struct cryptd_hash_request_ctx { struct shash_desc desc; }; -struct cryptd_aead_ctx { - struct crypto_aead *child; -}; - -struct cryptd_aead_request_ctx { - crypto_completion_t complete; -}; - static void cryptd_queue_worker(struct work_struct *work); static int cryptd_init_queue(struct cryptd_queue *queue, @@ -622,144 +601,6 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, return err; } -static void cryptd_aead_crypt(struct aead_request *req, - struct crypto_aead *child, - int err, - int (*crypt)(struct aead_request *req)) -{ - struct cryptd_aead_request_ctx *rctx; - rctx = aead_request_ctx(req); - - if (unlikely(err == -EINPROGRESS)) - goto out; - aead_request_set_tfm(req, child); - err = crypt( req ); - req->base.complete = rctx->complete; -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static void cryptd_aead_encrypt(struct crypto_async_request *areq, int err) -{ - struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm); - struct crypto_aead *child = ctx->child; - struct aead_request *req; - - req = container_of(areq, struct aead_request, base); - cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->encrypt); -} - -static void cryptd_aead_decrypt(struct crypto_async_request *areq, int err) -{ - struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm); - struct crypto_aead *child = ctx->child; - struct aead_request *req; - - req = container_of(areq, struct aead_request, base); - cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->decrypt); -} - -static int cryptd_aead_enqueue(struct aead_request *req, - crypto_completion_t complete) -{ - struct cryptd_aead_request_ctx *rctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cryptd_queue *queue = cryptd_get_queue(crypto_aead_tfm(tfm)); - - rctx->complete = req->base.complete; - req->base.complete = complete; - return cryptd_enqueue_request(queue, &req->base); -} - -static int cryptd_aead_encrypt_enqueue(struct aead_request *req) -{ - return cryptd_aead_enqueue(req, cryptd_aead_encrypt ); -} - -static int cryptd_aead_decrypt_enqueue(struct aead_request *req) -{ - return cryptd_aead_enqueue(req, cryptd_aead_decrypt ); -} - -static int cryptd_aead_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct aead_instance_ctx *ictx = crypto_instance_ctx(inst); - struct crypto_aead_spawn *spawn = &ictx->aead_spawn; - struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_aead *cipher; - - cipher = crypto_spawn_aead(spawn); - if (IS_ERR(cipher)) - return PTR_ERR(cipher); - - crypto_aead_set_flags(cipher, CRYPTO_TFM_REQ_MAY_SLEEP); - ctx->child = cipher; - tfm->crt_aead.reqsize = sizeof(struct cryptd_aead_request_ctx); - return 0; -} - -static void cryptd_aead_exit_tfm(struct crypto_tfm *tfm) -{ - struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_aead(ctx->child); -} - -static int cryptd_create_aead(struct crypto_template *tmpl, - struct rtattr **tb, - struct cryptd_queue *queue) -{ - struct aead_instance_ctx *ctx; - struct crypto_instance *inst; - struct crypto_alg *alg; - int err; - - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_AEAD, - CRYPTO_ALG_TYPE_MASK); - if (IS_ERR(alg)) - return PTR_ERR(alg); - - inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx)); - err = PTR_ERR(inst); - if (IS_ERR(inst)) - goto out_put_alg; - - ctx = crypto_instance_ctx(inst); - ctx->queue = queue; - - err = crypto_init_spawn(&ctx->aead_spawn.base, alg, inst, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); - if (err) - goto out_free_inst; - - inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; - inst->alg.cra_type = alg->cra_type; - inst->alg.cra_ctxsize = sizeof(struct cryptd_aead_ctx); - inst->alg.cra_init = cryptd_aead_init_tfm; - inst->alg.cra_exit = cryptd_aead_exit_tfm; - inst->alg.cra_aead.setkey = alg->cra_aead.setkey; - inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize; - inst->alg.cra_aead.geniv = alg->cra_aead.geniv; - inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize; - inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize; - inst->alg.cra_aead.encrypt = cryptd_aead_encrypt_enqueue; - inst->alg.cra_aead.decrypt = cryptd_aead_decrypt_enqueue; - inst->alg.cra_aead.givencrypt = alg->cra_aead.givencrypt; - inst->alg.cra_aead.givdecrypt = alg->cra_aead.givdecrypt; - - err = crypto_register_instance(tmpl, inst); - if (err) { - crypto_drop_spawn(&ctx->aead_spawn.base); -out_free_inst: - kfree(inst); - } -out_put_alg: - crypto_mod_put(alg); - return err; -} - static struct cryptd_queue queue; static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb) @@ -775,8 +616,6 @@ static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb) return cryptd_create_blkcipher(tmpl, tb, &queue); case CRYPTO_ALG_TYPE_DIGEST: return cryptd_create_hash(tmpl, tb, &queue); - case CRYPTO_ALG_TYPE_AEAD: - return cryptd_create_aead(tmpl, tb, &queue); } return -EINVAL; @@ -786,21 +625,16 @@ static void cryptd_free(struct crypto_instance *inst) { struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst); struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst); - struct aead_instance_ctx *aead_ctx = crypto_instance_ctx(inst); switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_AHASH: crypto_drop_shash(&hctx->spawn); kfree(ahash_instance(inst)); return; - case CRYPTO_ALG_TYPE_AEAD: - crypto_drop_spawn(&aead_ctx->aead_spawn.base); - kfree(inst); - return; - default: - crypto_drop_spawn(&ctx->spawn); - kfree(inst); } + + crypto_drop_spawn(&ctx->spawn); + kfree(inst); } static struct crypto_template cryptd_tmpl = { @@ -890,40 +724,6 @@ void cryptd_free_ahash(struct cryptd_ahash *tfm) } EXPORT_SYMBOL_GPL(cryptd_free_ahash); -struct cryptd_aead *cryptd_alloc_aead(const char *alg_name, - u32 type, u32 mask) -{ - char cryptd_alg_name[CRYPTO_MAX_ALG_NAME]; - struct crypto_aead *tfm; - - if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME, - "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME) - return ERR_PTR(-EINVAL); - tfm = crypto_alloc_aead(cryptd_alg_name, type, mask); - if (IS_ERR(tfm)) - return ERR_CAST(tfm); - if (tfm->base.__crt_alg->cra_module != THIS_MODULE) { - crypto_free_aead(tfm); - return ERR_PTR(-EINVAL); - } - return __cryptd_aead_cast(tfm); -} -EXPORT_SYMBOL_GPL(cryptd_alloc_aead); - -struct crypto_aead *cryptd_aead_child(struct cryptd_aead *tfm) -{ - struct cryptd_aead_ctx *ctx; - ctx = crypto_aead_ctx(&tfm->base); - return ctx->child; -} -EXPORT_SYMBOL_GPL(cryptd_aead_child); - -void cryptd_free_aead(struct cryptd_aead *tfm) -{ - crypto_free_aead(&tfm->base); -} -EXPORT_SYMBOL_GPL(cryptd_free_aead); - static int __init cryptd_init(void) { int err; diff --git a/trunk/drivers/ata/pata_bf54x.c b/trunk/drivers/ata/pata_bf54x.c index 7aed5c792597..ec2c777fcdb0 100644 --- a/trunk/drivers/ata/pata_bf54x.c +++ b/trunk/drivers/ata/pata_bf54x.c @@ -1588,7 +1588,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) host->ports[0]->ioaddr.ctl_addr = (void *)res->start; if (peripheral_request_list(atapi_io_port, "atapi-io-port")) { - dev_err(&pdev->dev, "Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "Requesting Peripherals faild\n"); return -EFAULT; } diff --git a/trunk/drivers/ata/pata_it821x.c b/trunk/drivers/ata/pata_it821x.c index aa0e0c51cc08..bf88f71a21f4 100644 --- a/trunk/drivers/ata/pata_it821x.c +++ b/trunk/drivers/ata/pata_it821x.c @@ -15,8 +15,8 @@ * May be copied or modified under the terms of the GNU General Public License * Based in part on the ITE vendor provided SCSI driver. * - * Documentation available from IT8212F_V04.pdf - * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91 + * Documentation available from + * http://www.ite.com.tw/pc/IT8212F_V04.pdf * Some other documents are NDA. * * The ITE8212 isn't exactly a standard IDE controller. It has two diff --git a/trunk/drivers/atm/Kconfig b/trunk/drivers/atm/Kconfig index 31c60101a69a..be7461c9a87e 100644 --- a/trunk/drivers/atm/Kconfig +++ b/trunk/drivers/atm/Kconfig @@ -301,7 +301,7 @@ config ATM_IA control memory (128K-1KVC, 512K-4KVC), the size of the packet memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, UTP155, UTP25, DS3 and E3). Go to: - + for more info about the cards. Say Y (or M to compile as a module named iphase) here if you have one of these cards. diff --git a/trunk/drivers/base/core.c b/trunk/drivers/base/core.c index 6ed645411c40..2cb49a93b1e6 100644 --- a/trunk/drivers/base/core.c +++ b/trunk/drivers/base/core.c @@ -233,7 +233,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, __func__, retval); } - /* have the device type specific function add its stuff */ + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { retval = dev->type->uevent(dev, env); if (retval) diff --git a/trunk/drivers/char/agp/Kconfig b/trunk/drivers/char/agp/Kconfig index fcd867d923ba..5ddf67e76f8b 100644 --- a/trunk/drivers/char/agp/Kconfig +++ b/trunk/drivers/char/agp/Kconfig @@ -34,7 +34,7 @@ config AGP_ALI X on the following ALi chipsets. The supported chipsets include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. For the ALi-chipset question, ALi suggests you refer to - . + . The M1541 chipset can do AGP 1x and 2x, but note that there is an acknowledged incompatibility with Matrox G200 cards. Due to diff --git a/trunk/drivers/char/agp/i460-agp.c b/trunk/drivers/char/agp/i460-agp.c index 75b763cb3ea1..e763d3312ce7 100644 --- a/trunk/drivers/char/agp/i460-agp.c +++ b/trunk/drivers/char/agp/i460-agp.c @@ -1,7 +1,7 @@ /* * For documentation on the i460 AGP interface, see Chapter 7 (AGP Subsystem) of * the "Intel 460GTX Chipset Software Developer's Manual": - * http://www.intel.com/design/archives/itanium/downloads/248704.htm + * http://developer.intel.com/design/itanium/downloads/24870401s.htm */ /* * 460GX support by Chris Ahna diff --git a/trunk/drivers/char/apm-emulation.c b/trunk/drivers/char/apm-emulation.c index 45b987c9889e..3022801669b1 100644 --- a/trunk/drivers/char/apm-emulation.c +++ b/trunk/drivers/char/apm-emulation.c @@ -7,8 +7,8 @@ * Intel Corporation, Microsoft Corporation. Advanced Power Management * (APM) BIOS Interface Specification, Revision 1.2, February 1996. * - * This document is available from Microsoft at: - * http://www.microsoft.com/whdc/archive/amp_12.mspx + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] */ #include #include diff --git a/trunk/drivers/char/ipmi/ipmi_bt_sm.c b/trunk/drivers/char/ipmi/ipmi_bt_sm.c index 3ed20e8abc0d..7b98c067190a 100644 --- a/trunk/drivers/char/ipmi/ipmi_bt_sm.c +++ b/trunk/drivers/char/ipmi/ipmi_bt_sm.c @@ -2,7 +2,7 @@ * ipmi_bt_sm.c * * The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part - * of the driver architecture at http://sourceforge.net/projects/openipmi + * of the driver architecture at http://sourceforge.net/project/openipmi * * Author: Rocky Craig * diff --git a/trunk/drivers/char/ipmi/ipmi_si_intf.c b/trunk/drivers/char/ipmi/ipmi_si_intf.c index e537610d2f09..7bd7c45b53ef 100644 --- a/trunk/drivers/char/ipmi/ipmi_si_intf.c +++ b/trunk/drivers/char/ipmi/ipmi_si_intf.c @@ -1974,7 +1974,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info) /* * Defined at - * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf + * http://h21007.www2.hp.com/portal/download/files + * /unprot/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; diff --git a/trunk/drivers/char/n_r3964.c b/trunk/drivers/char/n_r3964.c index 88dda0c45ee0..a98290d7a2c5 100644 --- a/trunk/drivers/char/n_r3964.c +++ b/trunk/drivers/char/n_r3964.c @@ -4,6 +4,7 @@ * Copyright by * Philips Automation Projects * Kassel (Germany) + * http://www.pap-philips.de * ----------------------------------------------------------- * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff --git a/trunk/drivers/char/pcmcia/Kconfig b/trunk/drivers/char/pcmcia/Kconfig index 6614416a8623..ffa0efce0aed 100644 --- a/trunk/drivers/char/pcmcia/Kconfig +++ b/trunk/drivers/char/pcmcia/Kconfig @@ -28,7 +28,7 @@ config CARDMAN_4000 This kernel driver requires additional userspace support, either by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/), - or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc). + or via the cm4000 backend of OpenCT (http://www.opensc.com/). config CARDMAN_4040 tristate "Omnikey CardMan 4040 support" @@ -41,7 +41,7 @@ config CARDMAN_4040 in I/O space. To use the kernel driver, you will need either the PC/SC ifdhandler provided from the Omnikey homepage (http://www.omnikey.com/), or a current development version of OpenCT - (http://www.opensc-project.org/opensc). + (http://www.opensc.org/). config IPWIRELESS tristate "IPWireless 3G UMTS PCMCIA card support" diff --git a/trunk/drivers/char/pcmcia/cm4000_cs.c b/trunk/drivers/char/pcmcia/cm4000_cs.c index d962f25dcc2a..6835c23e9a51 100644 --- a/trunk/drivers/char/pcmcia/cm4000_cs.c +++ b/trunk/drivers/char/pcmcia/cm4000_cs.c @@ -1666,7 +1666,7 @@ static int cmm_open(struct inode *inode, struct file *filp) /* opening will always block since the * monitor will be started by open, which * means we have to wait for ATR becoming - * valid = block until valid (or card + * vaild = block until valid (or card * inserted) */ if (filp->f_flags & O_NONBLOCK) { diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c index 4bef6ab83622..8ef16490810c 100644 --- a/trunk/drivers/char/stallion.c +++ b/trunk/drivers/char/stallion.c @@ -3181,7 +3181,7 @@ static void stl_cd1400flush(struct stlport *portp) /* * Return the current state of data flow on this port. This is only - * really interesting when determining if data has fully completed + * really interresting when determining if data has fully completed * transmission or not... This is easy for the cd1400, it accurately * maintains the busy port flag. */ @@ -4131,7 +4131,7 @@ static void stl_sc26198flush(struct stlport *portp) /* * Return the current state of data flow on this port. This is only - * really interesting when determining if data has fully completed + * really interresting when determining if data has fully completed * transmission or not... The sc26198 interrupt scheme cannot * determine when all data has actually drained, so we need to * check the port statusy register to be sure. diff --git a/trunk/drivers/char/tpm/Kconfig b/trunk/drivers/char/tpm/Kconfig index f6595aba4f0f..4dc338f3d1aa 100644 --- a/trunk/drivers/char/tpm/Kconfig +++ b/trunk/drivers/char/tpm/Kconfig @@ -58,6 +58,6 @@ config TCG_INFINEON To compile this driver as a module, choose M here; the module will be called tpm_infineon. Further information on this driver and the supported hardware - can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ + can be found at http://www.prosec.rub.de/tpm endif # TCG_TPM diff --git a/trunk/drivers/char/tpm/tpm_infineon.c b/trunk/drivers/char/tpm/tpm_infineon.c index 76da32e11f18..f58440791e65 100644 --- a/trunk/drivers/char/tpm/tpm_infineon.c +++ b/trunk/drivers/char/tpm/tpm_infineon.c @@ -7,7 +7,7 @@ * Copyright (C) 2005, Marcel Selhorst * Sirrix AG - security technologies, http://www.sirrix.com and * Applied Data Security Group, Ruhr-University Bochum, Germany - * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ + * Project-Homepage: http://www.prosec.rub.de/tpm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/trunk/drivers/crypto/Kconfig b/trunk/drivers/crypto/Kconfig index eab2cf7a0269..ea0b3863ad0f 100644 --- a/trunk/drivers/crypto/Kconfig +++ b/trunk/drivers/crypto/Kconfig @@ -172,7 +172,6 @@ config CRYPTO_DEV_MV_CESA config CRYPTO_DEV_NIAGARA2 tristate "Niagara2 Stream Processing Unit driver" - select CRYPTO_DES select CRYPTO_ALGAPI depends on SPARC64 help @@ -244,12 +243,4 @@ config CRYPTO_DEV_OMAP_SHAM OMAP processors have SHA1/MD5 hw accelerator. Select this if you want to use the OMAP module for SHA1/MD5 algorithms. -config CRYPTO_DEV_OMAP_AES - tristate "Support for OMAP AES hw engine" - depends on ARCH_OMAP2 || ARCH_OMAP3 - select CRYPTO_AES - help - OMAP processors have AES module accelerator. Select this if you - want to use the OMAP module for AES algorithms. - endif # CRYPTO_HW diff --git a/trunk/drivers/crypto/Makefile b/trunk/drivers/crypto/Makefile index 256697330a41..6dbbe00c4524 100644 --- a/trunk/drivers/crypto/Makefile +++ b/trunk/drivers/crypto/Makefile @@ -2,12 +2,11 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o -n2_crypto-y := n2_core.o n2_asm.o +n2_crypto-objs := n2_core.o n2_asm.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o -obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o diff --git a/trunk/drivers/crypto/amcc/Makefile b/trunk/drivers/crypto/amcc/Makefile index 5c0c62b65d69..aa376e8d5ed5 100644 --- a/trunk/drivers/crypto/amcc/Makefile +++ b/trunk/drivers/crypto/amcc/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o -crypto4xx-y := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o +crypto4xx-objs := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o diff --git a/trunk/drivers/crypto/hifn_795x.c b/trunk/drivers/crypto/hifn_795x.c index 0eac3da566ba..e449ac5627a5 100644 --- a/trunk/drivers/crypto/hifn_795x.c +++ b/trunk/drivers/crypto/hifn_795x.c @@ -2700,7 +2700,8 @@ static void __devexit hifn_remove(struct pci_dev *pdev) dev = pci_get_drvdata(pdev); if (dev) { - cancel_delayed_work_sync(&dev->work); + cancel_delayed_work(&dev->work); + flush_scheduled_work(); hifn_unregister_rng(dev); hifn_unregister_alg(dev); diff --git a/trunk/drivers/crypto/omap-aes.c b/trunk/drivers/crypto/omap-aes.c deleted file mode 100644 index 799ca517c121..000000000000 --- a/trunk/drivers/crypto/omap-aes.c +++ /dev/null @@ -1,948 +0,0 @@ -/* - * Cryptographic API. - * - * Support for OMAP AES HW acceleration. - * - * Copyright (c) 2010 Nokia Corporation - * Author: Dmitry Kasatkin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - */ - -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* OMAP TRM gives bitfields as start:end, where start is the higher bit - number. For example 7:0 */ -#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) -#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) - -#define AES_REG_KEY(x) (0x1C - ((x ^ 0x01) * 0x04)) -#define AES_REG_IV(x) (0x20 + ((x) * 0x04)) - -#define AES_REG_CTRL 0x30 -#define AES_REG_CTRL_CTR_WIDTH (1 << 7) -#define AES_REG_CTRL_CTR (1 << 6) -#define AES_REG_CTRL_CBC (1 << 5) -#define AES_REG_CTRL_KEY_SIZE (3 << 3) -#define AES_REG_CTRL_DIRECTION (1 << 2) -#define AES_REG_CTRL_INPUT_READY (1 << 1) -#define AES_REG_CTRL_OUTPUT_READY (1 << 0) - -#define AES_REG_DATA 0x34 -#define AES_REG_DATA_N(x) (0x34 + ((x) * 0x04)) - -#define AES_REG_REV 0x44 -#define AES_REG_REV_MAJOR 0xF0 -#define AES_REG_REV_MINOR 0x0F - -#define AES_REG_MASK 0x48 -#define AES_REG_MASK_SIDLE (1 << 6) -#define AES_REG_MASK_START (1 << 5) -#define AES_REG_MASK_DMA_OUT_EN (1 << 3) -#define AES_REG_MASK_DMA_IN_EN (1 << 2) -#define AES_REG_MASK_SOFTRESET (1 << 1) -#define AES_REG_AUTOIDLE (1 << 0) - -#define AES_REG_SYSSTATUS 0x4C -#define AES_REG_SYSSTATUS_RESETDONE (1 << 0) - -#define DEFAULT_TIMEOUT (5*HZ) - -#define FLAGS_MODE_MASK 0x000f -#define FLAGS_ENCRYPT BIT(0) -#define FLAGS_CBC BIT(1) -#define FLAGS_GIV BIT(2) - -#define FLAGS_NEW_KEY BIT(4) -#define FLAGS_NEW_IV BIT(5) -#define FLAGS_INIT BIT(6) -#define FLAGS_FAST BIT(7) -#define FLAGS_BUSY 8 - -struct omap_aes_ctx { - struct omap_aes_dev *dd; - - int keylen; - u32 key[AES_KEYSIZE_256 / sizeof(u32)]; - unsigned long flags; -}; - -struct omap_aes_reqctx { - unsigned long mode; -}; - -#define OMAP_AES_QUEUE_LENGTH 1 -#define OMAP_AES_CACHE_SIZE 0 - -struct omap_aes_dev { - struct list_head list; - unsigned long phys_base; - void __iomem *io_base; - struct clk *iclk; - struct omap_aes_ctx *ctx; - struct device *dev; - unsigned long flags; - - u32 *iv; - u32 ctrl; - - spinlock_t lock; - struct crypto_queue queue; - - struct tasklet_struct task; - - struct ablkcipher_request *req; - size_t total; - struct scatterlist *in_sg; - size_t in_offset; - struct scatterlist *out_sg; - size_t out_offset; - - size_t buflen; - void *buf_in; - size_t dma_size; - int dma_in; - int dma_lch_in; - dma_addr_t dma_addr_in; - void *buf_out; - int dma_out; - int dma_lch_out; - dma_addr_t dma_addr_out; -}; - -/* keep registered devices data here */ -static LIST_HEAD(dev_list); -static DEFINE_SPINLOCK(list_lock); - -static inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset) -{ - return __raw_readl(dd->io_base + offset); -} - -static inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset, - u32 value) -{ - __raw_writel(value, dd->io_base + offset); -} - -static inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset, - u32 value, u32 mask) -{ - u32 val; - - val = omap_aes_read(dd, offset); - val &= ~mask; - val |= value; - omap_aes_write(dd, offset, val); -} - -static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset, - u32 *value, int count) -{ - for (; count--; value++, offset += 4) - omap_aes_write(dd, offset, *value); -} - -static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit) -{ - unsigned long timeout = jiffies + DEFAULT_TIMEOUT; - - while (!(omap_aes_read(dd, offset) & bit)) { - if (time_is_before_jiffies(timeout)) { - dev_err(dd->dev, "omap-aes timeout\n"); - return -ETIMEDOUT; - } - } - return 0; -} - -static int omap_aes_hw_init(struct omap_aes_dev *dd) -{ - int err = 0; - - clk_enable(dd->iclk); - if (!(dd->flags & FLAGS_INIT)) { - /* is it necessary to reset before every operation? */ - omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET, - AES_REG_MASK_SOFTRESET); - /* - * prevent OCP bus error (SRESP) in case an access to the module - * is performed while the module is coming out of soft reset - */ - __asm__ __volatile__("nop"); - __asm__ __volatile__("nop"); - - err = omap_aes_wait(dd, AES_REG_SYSSTATUS, - AES_REG_SYSSTATUS_RESETDONE); - if (!err) - dd->flags |= FLAGS_INIT; - } - - return err; -} - -static void omap_aes_hw_cleanup(struct omap_aes_dev *dd) -{ - clk_disable(dd->iclk); -} - -static void omap_aes_write_ctrl(struct omap_aes_dev *dd) -{ - unsigned int key32; - int i; - u32 val, mask; - - val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); - if (dd->flags & FLAGS_CBC) - val |= AES_REG_CTRL_CBC; - if (dd->flags & FLAGS_ENCRYPT) - val |= AES_REG_CTRL_DIRECTION; - - if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) && - !(dd->ctx->flags & FLAGS_NEW_KEY)) - goto out; - - /* only need to write control registers for new settings */ - - dd->ctrl = val; - - val = 0; - if (dd->dma_lch_out >= 0) - val |= AES_REG_MASK_DMA_OUT_EN; - if (dd->dma_lch_in >= 0) - val |= AES_REG_MASK_DMA_IN_EN; - - mask = AES_REG_MASK_DMA_IN_EN | AES_REG_MASK_DMA_OUT_EN; - - omap_aes_write_mask(dd, AES_REG_MASK, val, mask); - - pr_debug("Set key\n"); - key32 = dd->ctx->keylen / sizeof(u32); - /* set a key */ - for (i = 0; i < key32; i++) { - omap_aes_write(dd, AES_REG_KEY(i), - __le32_to_cpu(dd->ctx->key[i])); - } - dd->ctx->flags &= ~FLAGS_NEW_KEY; - - if (dd->flags & FLAGS_NEW_IV) { - pr_debug("Set IV\n"); - omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4); - dd->flags &= ~FLAGS_NEW_IV; - } - - mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION | - AES_REG_CTRL_KEY_SIZE; - - omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask); - -out: - /* start DMA or disable idle mode */ - omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, - AES_REG_MASK_START); -} - -static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx) -{ - struct omap_aes_dev *dd = NULL, *tmp; - - spin_lock_bh(&list_lock); - if (!ctx->dd) { - list_for_each_entry(tmp, &dev_list, list) { - /* FIXME: take fist available aes core */ - dd = tmp; - break; - } - ctx->dd = dd; - } else { - /* already found before */ - dd = ctx->dd; - } - spin_unlock_bh(&list_lock); - - return dd; -} - -static void omap_aes_dma_callback(int lch, u16 ch_status, void *data) -{ - struct omap_aes_dev *dd = data; - - if (lch == dd->dma_lch_out) - tasklet_schedule(&dd->task); -} - -static int omap_aes_dma_init(struct omap_aes_dev *dd) -{ - int err = -ENOMEM; - - dd->dma_lch_out = -1; - dd->dma_lch_in = -1; - - dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE); - dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE); - dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE; - dd->buflen &= ~(AES_BLOCK_SIZE - 1); - - if (!dd->buf_in || !dd->buf_out) { - dev_err(dd->dev, "unable to alloc pages.\n"); - goto err_alloc; - } - - /* MAP here */ - dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen, - DMA_TO_DEVICE); - if (dma_mapping_error(dd->dev, dd->dma_addr_in)) { - dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); - err = -EINVAL; - goto err_map_in; - } - - dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen, - DMA_FROM_DEVICE); - if (dma_mapping_error(dd->dev, dd->dma_addr_out)) { - dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); - err = -EINVAL; - goto err_map_out; - } - - err = omap_request_dma(dd->dma_in, "omap-aes-rx", - omap_aes_dma_callback, dd, &dd->dma_lch_in); - if (err) { - dev_err(dd->dev, "Unable to request DMA channel\n"); - goto err_dma_in; - } - err = omap_request_dma(dd->dma_out, "omap-aes-tx", - omap_aes_dma_callback, dd, &dd->dma_lch_out); - if (err) { - dev_err(dd->dev, "Unable to request DMA channel\n"); - goto err_dma_out; - } - - omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - - omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - - return 0; - -err_dma_out: - omap_free_dma(dd->dma_lch_in); -err_dma_in: - dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, - DMA_FROM_DEVICE); -err_map_out: - dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE); -err_map_in: - free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE); - free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE); -err_alloc: - if (err) - pr_err("error: %d\n", err); - return err; -} - -static void omap_aes_dma_cleanup(struct omap_aes_dev *dd) -{ - omap_free_dma(dd->dma_lch_out); - omap_free_dma(dd->dma_lch_in); - dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, - DMA_FROM_DEVICE); - dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE); - free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE); - free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE); -} - -static void sg_copy_buf(void *buf, struct scatterlist *sg, - unsigned int start, unsigned int nbytes, int out) -{ - struct scatter_walk walk; - - if (!nbytes) - return; - - scatterwalk_start(&walk, sg); - scatterwalk_advance(&walk, start); - scatterwalk_copychunks(buf, &walk, nbytes, out); - scatterwalk_done(&walk, out, 0); -} - -static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, - size_t buflen, size_t total, int out) -{ - unsigned int count, off = 0; - - while (buflen && total) { - count = min((*sg)->length - *offset, total); - count = min(count, buflen); - - if (!count) - return off; - - sg_copy_buf(buf + off, *sg, *offset, count, out); - - off += count; - buflen -= count; - *offset += count; - total -= count; - - if (*offset == (*sg)->length) { - *sg = sg_next(*sg); - if (*sg) - *offset = 0; - else - total = 0; - } - } - - return off; -} - -static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, - dma_addr_t dma_addr_out, int length) -{ - struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct omap_aes_dev *dd = ctx->dd; - int len32; - - pr_debug("len: %d\n", length); - - dd->dma_size = length; - - if (!(dd->flags & FLAGS_FAST)) - dma_sync_single_for_device(dd->dev, dma_addr_in, length, - DMA_TO_DEVICE); - - len32 = DIV_ROUND_UP(length, sizeof(u32)); - - /* IN */ - omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32, - len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in, - OMAP_DMA_DST_SYNC); - - omap_set_dma_src_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_POST_INC, - dma_addr_in, 0, 0); - - /* OUT */ - omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32, - len32, 1, OMAP_DMA_SYNC_PACKET, - dd->dma_out, OMAP_DMA_SRC_SYNC); - - omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC, - dma_addr_out, 0, 0); - - omap_start_dma(dd->dma_lch_in); - omap_start_dma(dd->dma_lch_out); - - omap_aes_write_ctrl(dd); - - return 0; -} - -static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) -{ - struct crypto_tfm *tfm = crypto_ablkcipher_tfm( - crypto_ablkcipher_reqtfm(dd->req)); - int err, fast = 0, in, out; - size_t count; - dma_addr_t addr_in, addr_out; - - pr_debug("total: %d\n", dd->total); - - if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) { - /* check for alignment */ - in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)); - out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)); - - fast = in && out; - } - - if (fast) { - count = min(dd->total, sg_dma_len(dd->in_sg)); - count = min(count, sg_dma_len(dd->out_sg)); - - if (count != dd->total) - return -EINVAL; - - pr_debug("fast\n"); - - err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); - if (!err) { - dev_err(dd->dev, "dma_map_sg() error\n"); - return -EINVAL; - } - - err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); - if (!err) { - dev_err(dd->dev, "dma_map_sg() error\n"); - dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); - return -EINVAL; - } - - addr_in = sg_dma_address(dd->in_sg); - addr_out = sg_dma_address(dd->out_sg); - - dd->flags |= FLAGS_FAST; - - } else { - /* use cache buffers */ - count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in, - dd->buflen, dd->total, 0); - - addr_in = dd->dma_addr_in; - addr_out = dd->dma_addr_out; - - dd->flags &= ~FLAGS_FAST; - - } - - dd->total -= count; - - err = omap_aes_hw_init(dd); - - err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count); - - return err; -} - -static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) -{ - struct omap_aes_ctx *ctx; - - pr_debug("err: %d\n", err); - - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req)); - - if (!dd->total) - dd->req->base.complete(&dd->req->base, err); -} - -static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) -{ - int err = 0; - size_t count; - - pr_debug("total: %d\n", dd->total); - - omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START); - - omap_aes_hw_cleanup(dd); - - omap_stop_dma(dd->dma_lch_in); - omap_stop_dma(dd->dma_lch_out); - - if (dd->flags & FLAGS_FAST) { - dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); - dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); - } else { - dma_sync_single_for_device(dd->dev, dd->dma_addr_out, - dd->dma_size, DMA_FROM_DEVICE); - - /* copy data */ - count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out, - dd->buflen, dd->dma_size, 1); - if (count != dd->dma_size) { - err = -EINVAL; - pr_err("not all data converted: %u\n", count); - } - } - - if (err || !dd->total) - omap_aes_finish_req(dd, err); - - return err; -} - -static int omap_aes_handle_req(struct omap_aes_dev *dd) -{ - struct crypto_async_request *async_req, *backlog; - struct omap_aes_ctx *ctx; - struct omap_aes_reqctx *rctx; - struct ablkcipher_request *req; - unsigned long flags; - - if (dd->total) - goto start; - - spin_lock_irqsave(&dd->lock, flags); - backlog = crypto_get_backlog(&dd->queue); - async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!async_req) - return 0; - - if (backlog) - backlog->complete(backlog, -EINPROGRESS); - - req = ablkcipher_request_cast(async_req); - - pr_debug("get new req\n"); - - /* assign new request to device */ - dd->req = req; - dd->total = req->nbytes; - dd->in_offset = 0; - dd->in_sg = req->src; - dd->out_offset = 0; - dd->out_sg = req->dst; - - rctx = ablkcipher_request_ctx(req); - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); - rctx->mode &= FLAGS_MODE_MASK; - dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; - - dd->iv = req->info; - if ((dd->flags & FLAGS_CBC) && dd->iv) - dd->flags |= FLAGS_NEW_IV; - else - dd->flags &= ~FLAGS_NEW_IV; - - ctx->dd = dd; - if (dd->ctx != ctx) { - /* assign new context to device */ - dd->ctx = ctx; - ctx->flags |= FLAGS_NEW_KEY; - } - - if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) - pr_err("request size is not exact amount of AES blocks\n"); - -start: - return omap_aes_crypt_dma_start(dd); -} - -static void omap_aes_task(unsigned long data) -{ - struct omap_aes_dev *dd = (struct omap_aes_dev *)data; - int err; - - pr_debug("enter\n"); - - err = omap_aes_crypt_dma_stop(dd); - - err = omap_aes_handle_req(dd); - - pr_debug("exit\n"); -} - -static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) -{ - struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx( - crypto_ablkcipher_reqtfm(req)); - struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req); - struct omap_aes_dev *dd; - unsigned long flags; - int err; - - pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, - !!(mode & FLAGS_ENCRYPT), - !!(mode & FLAGS_CBC)); - - dd = omap_aes_find_dev(ctx); - if (!dd) - return -ENODEV; - - rctx->mode = mode; - - spin_lock_irqsave(&dd->lock, flags); - err = ablkcipher_enqueue_request(&dd->queue, req); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!test_and_set_bit(FLAGS_BUSY, &dd->flags)) - omap_aes_handle_req(dd); - - pr_debug("exit\n"); - - return err; -} - -/* ********************** ALG API ************************************ */ - -static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); - - if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && - keylen != AES_KEYSIZE_256) - return -EINVAL; - - pr_debug("enter, keylen: %d\n", keylen); - - memcpy(ctx->key, key, keylen); - ctx->keylen = keylen; - ctx->flags |= FLAGS_NEW_KEY; - - return 0; -} - -static int omap_aes_ecb_encrypt(struct ablkcipher_request *req) -{ - return omap_aes_crypt(req, FLAGS_ENCRYPT); -} - -static int omap_aes_ecb_decrypt(struct ablkcipher_request *req) -{ - return omap_aes_crypt(req, 0); -} - -static int omap_aes_cbc_encrypt(struct ablkcipher_request *req) -{ - return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); -} - -static int omap_aes_cbc_decrypt(struct ablkcipher_request *req) -{ - return omap_aes_crypt(req, FLAGS_CBC); -} - -static int omap_aes_cra_init(struct crypto_tfm *tfm) -{ - pr_debug("enter\n"); - - tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx); - - return 0; -} - -static void omap_aes_cra_exit(struct crypto_tfm *tfm) -{ - pr_debug("enter\n"); -} - -/* ********************** ALGS ************************************ */ - -static struct crypto_alg algs[] = { -{ - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-omap", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = omap_aes_cra_init, - .cra_exit = omap_aes_cra_exit, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = omap_aes_setkey, - .encrypt = omap_aes_ecb_encrypt, - .decrypt = omap_aes_ecb_decrypt, - } -}, -{ - .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-omap", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = omap_aes_cra_init, - .cra_exit = omap_aes_cra_exit, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = omap_aes_setkey, - .encrypt = omap_aes_cbc_encrypt, - .decrypt = omap_aes_cbc_decrypt, - } -} -}; - -static int omap_aes_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct omap_aes_dev *dd; - struct resource *res; - int err = -ENOMEM, i, j; - u32 reg; - - dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL); - if (dd == NULL) { - dev_err(dev, "unable to alloc data struct.\n"); - goto err_data; - } - dd->dev = dev; - platform_set_drvdata(pdev, dd); - - spin_lock_init(&dd->lock); - crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH); - - /* Get the base address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "invalid resource type\n"); - err = -ENODEV; - goto err_res; - } - dd->phys_base = res->start; - - /* Get the DMA */ - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) - dev_info(dev, "no DMA info\n"); - else - dd->dma_out = res->start; - - /* Get the DMA */ - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) - dev_info(dev, "no DMA info\n"); - else - dd->dma_in = res->start; - - /* Initializing the clock */ - dd->iclk = clk_get(dev, "ick"); - if (!dd->iclk) { - dev_err(dev, "clock intialization failed.\n"); - err = -ENODEV; - goto err_res; - } - - dd->io_base = ioremap(dd->phys_base, SZ_4K); - if (!dd->io_base) { - dev_err(dev, "can't ioremap\n"); - err = -ENOMEM; - goto err_io; - } - - clk_enable(dd->iclk); - reg = omap_aes_read(dd, AES_REG_REV); - dev_info(dev, "OMAP AES hw accel rev: %u.%u\n", - (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR); - clk_disable(dd->iclk); - - tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd); - - err = omap_aes_dma_init(dd); - if (err) - goto err_dma; - - INIT_LIST_HEAD(&dd->list); - spin_lock(&list_lock); - list_add_tail(&dd->list, &dev_list); - spin_unlock(&list_lock); - - for (i = 0; i < ARRAY_SIZE(algs); i++) { - pr_debug("i: %d\n", i); - INIT_LIST_HEAD(&algs[i].cra_list); - err = crypto_register_alg(&algs[i]); - if (err) - goto err_algs; - } - - pr_info("probe() done\n"); - - return 0; -err_algs: - for (j = 0; j < i; j++) - crypto_unregister_alg(&algs[j]); - omap_aes_dma_cleanup(dd); -err_dma: - tasklet_kill(&dd->task); - iounmap(dd->io_base); -err_io: - clk_put(dd->iclk); -err_res: - kfree(dd); - dd = NULL; -err_data: - dev_err(dev, "initialization failed.\n"); - return err; -} - -static int omap_aes_remove(struct platform_device *pdev) -{ - struct omap_aes_dev *dd = platform_get_drvdata(pdev); - int i; - - if (!dd) - return -ENODEV; - - spin_lock(&list_lock); - list_del(&dd->list); - spin_unlock(&list_lock); - - for (i = 0; i < ARRAY_SIZE(algs); i++) - crypto_unregister_alg(&algs[i]); - - tasklet_kill(&dd->task); - omap_aes_dma_cleanup(dd); - iounmap(dd->io_base); - clk_put(dd->iclk); - kfree(dd); - dd = NULL; - - return 0; -} - -static struct platform_driver omap_aes_driver = { - .probe = omap_aes_probe, - .remove = omap_aes_remove, - .driver = { - .name = "omap-aes", - .owner = THIS_MODULE, - }, -}; - -static int __init omap_aes_mod_init(void) -{ - pr_info("loading %s driver\n", "omap-aes"); - - if (!cpu_class_is_omap2() || omap_type() != OMAP2_DEVICE_TYPE_SEC) { - pr_err("Unsupported cpu\n"); - return -ENODEV; - } - - return platform_driver_register(&omap_aes_driver); -} - -static void __exit omap_aes_mod_exit(void) -{ - platform_driver_unregister(&omap_aes_driver); -} - -module_init(omap_aes_mod_init); -module_exit(omap_aes_mod_exit); - -MODULE_DESCRIPTION("OMAP AES hw acceleration support."); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Dmitry Kasatkin"); - diff --git a/trunk/drivers/crypto/omap-sham.c b/trunk/drivers/crypto/omap-sham.c index a081c7c7d03f..7d1485676886 100644 --- a/trunk/drivers/crypto/omap-sham.c +++ b/trunk/drivers/crypto/omap-sham.c @@ -311,8 +311,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, len32 = DIV_ROUND_UP(length, sizeof(u32)); omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32, - 1, OMAP_DMA_SYNC_PACKET, dd->dma, - OMAP_DMA_DST_SYNC_PREFETCH); + 1, OMAP_DMA_SYNC_PACKET, dd->dma, OMAP_DMA_DST_SYNC); omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); @@ -1073,9 +1072,6 @@ static int omap_sham_dma_init(struct omap_sham_dev *dd) omap_set_dma_dest_burst_mode(dd->dma_lch, OMAP_DMA_DATA_BURST_16); - omap_set_dma_src_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_4); - return 0; } diff --git a/trunk/drivers/crypto/talitos.c b/trunk/drivers/crypto/talitos.c index b879c3f5d7c0..4bcd825b5739 100644 --- a/trunk/drivers/crypto/talitos.c +++ b/trunk/drivers/crypto/talitos.c @@ -161,7 +161,7 @@ struct talitos_private { static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr) { talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr)); - talitos_ptr->eptr = upper_32_bits(dma_addr); + talitos_ptr->eptr = cpu_to_be32(upper_32_bits(dma_addr)); } /* @@ -332,9 +332,10 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, /* GO! */ wmb(); - out_be32(priv->reg + TALITOS_FF(ch), upper_32_bits(request->dma_desc)); + out_be32(priv->reg + TALITOS_FF(ch), + cpu_to_be32(upper_32_bits(request->dma_desc))); out_be32(priv->reg + TALITOS_FF_LO(ch), - lower_32_bits(request->dma_desc)); + cpu_to_be32(lower_32_bits(request->dma_desc))); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); @@ -1750,14 +1751,14 @@ static int ahash_init_sha224_swinit(struct ahash_request *areq) ahash_init(areq); req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/ - req_ctx->hw_context[0] = SHA224_H0; - req_ctx->hw_context[1] = SHA224_H1; - req_ctx->hw_context[2] = SHA224_H2; - req_ctx->hw_context[3] = SHA224_H3; - req_ctx->hw_context[4] = SHA224_H4; - req_ctx->hw_context[5] = SHA224_H5; - req_ctx->hw_context[6] = SHA224_H6; - req_ctx->hw_context[7] = SHA224_H7; + req_ctx->hw_context[0] = cpu_to_be32(SHA224_H0); + req_ctx->hw_context[1] = cpu_to_be32(SHA224_H1); + req_ctx->hw_context[2] = cpu_to_be32(SHA224_H2); + req_ctx->hw_context[3] = cpu_to_be32(SHA224_H3); + req_ctx->hw_context[4] = cpu_to_be32(SHA224_H4); + req_ctx->hw_context[5] = cpu_to_be32(SHA224_H5); + req_ctx->hw_context[6] = cpu_to_be32(SHA224_H6); + req_ctx->hw_context[7] = cpu_to_be32(SHA224_H7); /* init 64-bit count */ req_ctx->hw_context[8] = 0; @@ -2332,7 +2333,8 @@ static int talitos_remove(struct platform_device *ofdev) talitos_unregister_rng(dev); for (i = 0; i < priv->num_channels; i++) - kfree(priv->chan[i].fifo); + if (priv->chan[i].fifo) + kfree(priv->chan[i].fifo); kfree(priv->chan); @@ -2387,9 +2389,6 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, DESC_HDR_MODE0_MDEU_SHA256; } break; - default: - dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type); - return ERR_PTR(-EINVAL); } alg->cra_module = THIS_MODULE; diff --git a/trunk/drivers/edac/Kconfig b/trunk/drivers/edac/Kconfig index f436a2fa9f38..9dbb28b9559f 100644 --- a/trunk/drivers/edac/Kconfig +++ b/trunk/drivers/edac/Kconfig @@ -209,13 +209,6 @@ config EDAC_I5100 Support for error detection and correction the Intel San Clemente MCH. -config EDAC_I7300 - tristate "Intel Clarksboro MCH" - depends on EDAC_MM_EDAC && X86 && PCI - help - Support for error detection and correction the Intel - Clarksboro MCH (Intel 7300 chipset). - config EDAC_MPC85XX tristate "Freescale MPC83xx / MPC85xx" depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx) diff --git a/trunk/drivers/edac/Makefile b/trunk/drivers/edac/Makefile index b3781399b38a..32c7bc93c525 100644 --- a/trunk/drivers/edac/Makefile +++ b/trunk/drivers/edac/Makefile @@ -27,7 +27,6 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5100) += i5100_edac.o obj-$(CONFIG_EDAC_I5400) += i5400_edac.o -obj-$(CONFIG_EDAC_I7300) += i7300_edac.o obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o obj-$(CONFIG_EDAC_E752X) += e752x_edac.o diff --git a/trunk/drivers/edac/edac_device_sysfs.c b/trunk/drivers/edac/edac_device_sysfs.c index 400de071cabc..2941dca91aae 100644 --- a/trunk/drivers/edac/edac_device_sysfs.c +++ b/trunk/drivers/edac/edac_device_sysfs.c @@ -1,7 +1,7 @@ /* * file for managing the edac_device class of devices for EDAC * - * (C) 2007 SoftwareBitMaker + * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com) * * This file may be distributed under the terms of the * GNU General Public License. diff --git a/trunk/drivers/edac/i7300_edac.c b/trunk/drivers/edac/i7300_edac.c deleted file mode 100644 index 05523b504271..000000000000 --- a/trunk/drivers/edac/i7300_edac.c +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * Intel 7300 class Memory Controllers kernel module (Clarksboro) - * - * This file may be distributed under the terms of the - * GNU General Public License version 2 only. - * - * Copyright (c) 2010 by: - * Mauro Carvalho Chehab - * - * Red Hat Inc. http://www.redhat.com - * - * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet - * http://www.intel.com/Assets/PDF/datasheet/318082.pdf - * - * TODO: The chipset allow checking for PCI Express errors also. Currently, - * the driver covers only memory error errors - * - * This driver uses "csrows" EDAC attribute to represent DIMM slot# - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "edac_core.h" - -/* - * Alter this version for the I7300 module when modifications are made - */ -#define I7300_REVISION " Ver: 1.0.0 " __DATE__ - -#define EDAC_MOD_STR "i7300_edac" - -#define i7300_printk(level, fmt, arg...) \ - edac_printk(level, "i7300", fmt, ##arg) - -#define i7300_mc_printk(mci, level, fmt, arg...) \ - edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg) - -/*********************************************** - * i7300 Limit constants Structs and static vars - ***********************************************/ - -/* - * Memory topology is organized as: - * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0) - * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0) - * Each channel can have to 8 DIMM sets (called as SLOTS) - * Slots should generally be filled in pairs - * Except on Single Channel mode of operation - * just slot 0/channel0 filled on this mode - * On normal operation mode, the two channels on a branch should be - * filled together for the same SLOT# - * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four - * channels on both branches should be filled - */ - -/* Limits for i7300 */ -#define MAX_SLOTS 8 -#define MAX_BRANCHES 2 -#define MAX_CH_PER_BRANCH 2 -#define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES) -#define MAX_MIR 3 - -#define to_channel(ch, branch) ((((branch)) << 1) | (ch)) - -#define to_csrow(slot, ch, branch) \ - (to_channel(ch, branch) | ((slot) << 2)) - -/* Device name and register DID (Device ID) */ -struct i7300_dev_info { - const char *ctl_name; /* name for this device */ - u16 fsb_mapping_errors; /* DID for the branchmap,control */ -}; - -/* Table of devices attributes supported by this driver */ -static const struct i7300_dev_info i7300_devs[] = { - { - .ctl_name = "I7300", - .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, - }, -}; - -struct i7300_dimm_info { - int megabytes; /* size, 0 means not present */ -}; - -/* driver private data structure */ -struct i7300_pvt { - struct pci_dev *pci_dev_16_0_fsb_ctlr; /* 16.0 */ - struct pci_dev *pci_dev_16_1_fsb_addr_map; /* 16.1 */ - struct pci_dev *pci_dev_16_2_fsb_err_regs; /* 16.2 */ - struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES]; /* 21.0 and 22.0 */ - - u16 tolm; /* top of low memory */ - u64 ambase; /* AMB BAR */ - - u32 mc_settings; /* Report several settings */ - u32 mc_settings_a; - - u16 mir[MAX_MIR]; /* Memory Interleave Reg*/ - - u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */ - u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */ - - /* DIMM information matrix, allocating architecture maximums */ - struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS]; - - /* Temporary buffer for use when preparing error messages */ - char *tmp_prt_buffer; -}; - -/* FIXME: Why do we need to have this static? */ -static struct edac_pci_ctl_info *i7300_pci; - -/*************************************************** - * i7300 Register definitions for memory enumeration - ***************************************************/ - -/* - * Device 16, - * Function 0: System Address (not documented) - * Function 1: Memory Branch Map, Control, Errors Register - */ - - /* OFFSETS for Function 0 */ -#define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ -#define MAXCH 0x56 /* Max Channel Number */ -#define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ - - /* OFFSETS for Function 1 */ -#define MC_SETTINGS 0x40 - #define IS_MIRRORED(mc) ((mc) & (1 << 16)) - #define IS_ECC_ENABLED(mc) ((mc) & (1 << 5)) - #define IS_RETRY_ENABLED(mc) ((mc) & (1 << 31)) - #define IS_SCRBALGO_ENHANCED(mc) ((mc) & (1 << 8)) - -#define MC_SETTINGS_A 0x58 - #define IS_SINGLE_MODE(mca) ((mca) & (1 << 14)) - -#define TOLM 0x6C - -#define MIR0 0x80 -#define MIR1 0x84 -#define MIR2 0x88 - -/* - * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available - * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it - * seems that we cannot use this information directly for the same usage. - * Each memory slot may have up to 2 AMB interfaces, one for income and another - * for outcome interface to the next slot. - * For now, the driver just stores the AMB present registers, but rely only at - * the MTR info to detect memory. - * Datasheet is also not clear about how to map each AMBPRESENT registers to - * one of the 4 available channels. - */ -#define AMBPRESENT_0 0x64 -#define AMBPRESENT_1 0x66 - -const static u16 mtr_regs[MAX_SLOTS] = { - 0x80, 0x84, 0x88, 0x8c, - 0x82, 0x86, 0x8a, 0x8e -}; - -/* - * Defines to extract the vaious fields from the - * MTRx - Memory Technology Registers - */ -#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8)) -#define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7)) -#define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4) -#define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4) -#define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0) -#define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) -#define MTR_DRAM_BANKS_ADDR_BITS 2 -#define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) -#define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) -#define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) - -#ifdef CONFIG_EDAC_DEBUG -/* MTR NUMROW */ -static const char *numrow_toString[] = { - "8,192 - 13 rows", - "16,384 - 14 rows", - "32,768 - 15 rows", - "65,536 - 16 rows" -}; - -/* MTR NUMCOL */ -static const char *numcol_toString[] = { - "1,024 - 10 columns", - "2,048 - 11 columns", - "4,096 - 12 columns", - "reserved" -}; -#endif - -/************************************************ - * i7300 Register definitions for error detection - ************************************************/ - -/* - * Device 16.1: FBD Error Registers - */ -#define FERR_FAT_FBD 0x98 -static const char *ferr_fat_fbd_name[] = { - [22] = "Non-Redundant Fast Reset Timeout", - [2] = ">Tmid Thermal event with intelligent throttling disabled", - [1] = "Memory or FBD configuration CRC read error", - [0] = "Memory Write error on non-redundant retry or " - "FBD configuration Write error on retry", -}; -#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28)) -#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) - -#define FERR_NF_FBD 0xa0 -static const char *ferr_nf_fbd_name[] = { - [24] = "DIMM-Spare Copy Completed", - [23] = "DIMM-Spare Copy Initiated", - [22] = "Redundant Fast Reset Timeout", - [21] = "Memory Write error on redundant retry", - [18] = "SPD protocol Error", - [17] = "FBD Northbound parity error on FBD Sync Status", - [16] = "Correctable Patrol Data ECC", - [15] = "Correctable Resilver- or Spare-Copy Data ECC", - [14] = "Correctable Mirrored Demand Data ECC", - [13] = "Correctable Non-Mirrored Demand Data ECC", - [11] = "Memory or FBD configuration CRC read error", - [10] = "FBD Configuration Write error on first attempt", - [9] = "Memory Write error on first attempt", - [8] = "Non-Aliased Uncorrectable Patrol Data ECC", - [7] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", - [6] = "Non-Aliased Uncorrectable Mirrored Demand Data ECC", - [5] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", - [4] = "Aliased Uncorrectable Patrol Data ECC", - [3] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", - [2] = "Aliased Uncorrectable Mirrored Demand Data ECC", - [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", - [0] = "Uncorrectable Data ECC on Replay", -}; -#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28)) -#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ - (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ - (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ - (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ - (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ - (1 << 1) | (1 << 0)) - -#define EMASK_FBD 0xa8 -#define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\ - (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\ - (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\ - (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\ - (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ - (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ - (1 << 1) | (1 << 0)) - -/* - * Device 16.2: Global Error Registers - */ - -#define FERR_GLOBAL_HI 0x48 -static const char *ferr_global_hi_name[] = { - [3] = "FSB 3 Fatal Error", - [2] = "FSB 2 Fatal Error", - [1] = "FSB 1 Fatal Error", - [0] = "FSB 0 Fatal Error", -}; -#define ferr_global_hi_is_fatal(errno) 1 - -#define FERR_GLOBAL_LO 0x40 -static const char *ferr_global_lo_name[] = { - [31] = "Internal MCH Fatal Error", - [30] = "Intel QuickData Technology Device Fatal Error", - [29] = "FSB1 Fatal Error", - [28] = "FSB0 Fatal Error", - [27] = "FBD Channel 3 Fatal Error", - [26] = "FBD Channel 2 Fatal Error", - [25] = "FBD Channel 1 Fatal Error", - [24] = "FBD Channel 0 Fatal Error", - [23] = "PCI Express Device 7Fatal Error", - [22] = "PCI Express Device 6 Fatal Error", - [21] = "PCI Express Device 5 Fatal Error", - [20] = "PCI Express Device 4 Fatal Error", - [19] = "PCI Express Device 3 Fatal Error", - [18] = "PCI Express Device 2 Fatal Error", - [17] = "PCI Express Device 1 Fatal Error", - [16] = "ESI Fatal Error", - [15] = "Internal MCH Non-Fatal Error", - [14] = "Intel QuickData Technology Device Non Fatal Error", - [13] = "FSB1 Non-Fatal Error", - [12] = "FSB 0 Non-Fatal Error", - [11] = "FBD Channel 3 Non-Fatal Error", - [10] = "FBD Channel 2 Non-Fatal Error", - [9] = "FBD Channel 1 Non-Fatal Error", - [8] = "FBD Channel 0 Non-Fatal Error", - [7] = "PCI Express Device 7 Non-Fatal Error", - [6] = "PCI Express Device 6 Non-Fatal Error", - [5] = "PCI Express Device 5 Non-Fatal Error", - [4] = "PCI Express Device 4 Non-Fatal Error", - [3] = "PCI Express Device 3 Non-Fatal Error", - [2] = "PCI Express Device 2 Non-Fatal Error", - [1] = "PCI Express Device 1 Non-Fatal Error", - [0] = "ESI Non-Fatal Error", -}; -#define ferr_global_lo_is_fatal(errno) ((errno < 16) ? 0 : 1) - -#define NRECMEMA 0xbe - #define NRECMEMA_BANK(v) (((v) >> 12) & 7) - #define NRECMEMA_RANK(v) (((v) >> 8) & 15) - -#define NRECMEMB 0xc0 - #define NRECMEMB_IS_WR(v) ((v) & (1 << 31)) - #define NRECMEMB_CAS(v) (((v) >> 16) & 0x1fff) - #define NRECMEMB_RAS(v) ((v) & 0xffff) - -#define REDMEMA 0xdc - -#define REDMEMB 0x7c - #define IS_SECOND_CH(v) ((v) * (1 << 17)) - -#define RECMEMA 0xe0 - #define RECMEMA_BANK(v) (((v) >> 12) & 7) - #define RECMEMA_RANK(v) (((v) >> 8) & 15) - -#define RECMEMB 0xe4 - #define RECMEMB_IS_WR(v) ((v) & (1 << 31)) - #define RECMEMB_CAS(v) (((v) >> 16) & 0x1fff) - #define RECMEMB_RAS(v) ((v) & 0xffff) - -/******************************************** - * i7300 Functions related to error detection - ********************************************/ - -/** - * get_err_from_table() - Gets the error message from a table - * @table: table name (array of char *) - * @size: number of elements at the table - * @pos: position of the element to be returned - * - * This is a small routine that gets the pos-th element of a table. If the - * element doesn't exist (or it is empty), it returns "reserved". - * Instead of calling it directly, the better is to call via the macro - * GET_ERR_FROM_TABLE(), that automatically checks the table size via - * ARRAY_SIZE() macro - */ -static const char *get_err_from_table(const char *table[], int size, int pos) -{ - if (unlikely(pos >= size)) - return "Reserved"; - - if (unlikely(!table[pos])) - return "Reserved"; - - return table[pos]; -} - -#define GET_ERR_FROM_TABLE(table, pos) \ - get_err_from_table(table, ARRAY_SIZE(table), pos) - -/** - * i7300_process_error_global() - Retrieve the hardware error information from - * the hardware global error registers and - * sends it to dmesg - * @mci: struct mem_ctl_info pointer - */ -static void i7300_process_error_global(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - u32 errnum, value; - unsigned long errors; - const char *specific; - bool is_fatal; - - pvt = mci->pvt_info; - - /* read in the 1st FATAL error register */ - pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_HI, &value); - if (unlikely(value)) { - errors = value; - errnum = find_first_bit(&errors, - ARRAY_SIZE(ferr_global_hi_name)); - specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum); - is_fatal = ferr_global_hi_is_fatal(errnum); - - /* Clear the error bit */ - pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_HI, value); - - goto error_global; - } - - pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_LO, &value); - if (unlikely(value)) { - errors = value; - errnum = find_first_bit(&errors, - ARRAY_SIZE(ferr_global_lo_name)); - specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum); - is_fatal = ferr_global_lo_is_fatal(errnum); - - /* Clear the error bit */ - pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_LO, value); - - goto error_global; - } - return; - -error_global: - i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n", - is_fatal ? "Fatal" : "NOT fatal", specific); -} - -/** - * i7300_process_fbd_error() - Retrieve the hardware error information from - * the FBD error registers and sends it via - * EDAC error API calls - * @mci: struct mem_ctl_info pointer - */ -static void i7300_process_fbd_error(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - u32 errnum, value; - u16 val16; - unsigned branch, channel, bank, rank, cas, ras; - u32 syndrome; - - unsigned long errors; - const char *specific; - bool is_wr; - - pvt = mci->pvt_info; - - /* read in the 1st FATAL error register */ - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_FAT_FBD, &value); - if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) { - errors = value & FERR_FAT_FBD_ERR_MASK ; - errnum = find_first_bit(&errors, - ARRAY_SIZE(ferr_fat_fbd_name)); - specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum); - - branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0; - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, - NRECMEMA, &val16); - bank = NRECMEMA_BANK(val16); - rank = NRECMEMA_RANK(val16); - - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - NRECMEMB, &value); - - is_wr = NRECMEMB_IS_WR(value); - cas = NRECMEMB_CAS(value); - ras = NRECMEMB_RAS(value); - - snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, - "FATAL (Branch=%d DRAM-Bank=%d %s " - "RAS=%d CAS=%d Err=0x%lx (%s))", - branch, bank, - is_wr ? "RDWR" : "RD", - ras, cas, - errors, specific); - - /* Call the helper to output message */ - edac_mc_handle_fbd_ue(mci, rank, branch << 1, - (branch << 1) + 1, - pvt->tmp_prt_buffer); - } - - /* read in the 1st NON-FATAL error register */ - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_NF_FBD, &value); - if (unlikely(value & FERR_NF_FBD_ERR_MASK)) { - errors = value & FERR_NF_FBD_ERR_MASK; - errnum = find_first_bit(&errors, - ARRAY_SIZE(ferr_nf_fbd_name)); - specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); - - /* Clear the error bit */ - pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_LO, value); - - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - REDMEMA, &syndrome); - - branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0; - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, - RECMEMA, &val16); - bank = RECMEMA_BANK(val16); - rank = RECMEMA_RANK(val16); - - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - RECMEMB, &value); - - is_wr = RECMEMB_IS_WR(value); - cas = RECMEMB_CAS(value); - ras = RECMEMB_RAS(value); - - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - REDMEMB, &value); - - channel = (branch << 1); - if (IS_SECOND_CH(value)) - channel++; - - /* Form out message */ - snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, - "Corrected error (Branch=%d, Channel %d), " - " DRAM-Bank=%d %s " - "RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))", - branch, channel, - bank, - is_wr ? "RDWR" : "RD", - ras, cas, - errors, syndrome, specific); - - /* - * Call the helper to output message - * NOTE: Errors are reported per-branch, and not per-channel - * Currently, we don't know how to identify the right - * channel. - */ - edac_mc_handle_fbd_ce(mci, rank, channel, - pvt->tmp_prt_buffer); - } - return; -} - -/** - * i7300_check_error() - Calls the error checking subroutines - * @mci: struct mem_ctl_info pointer - */ -static void i7300_check_error(struct mem_ctl_info *mci) -{ - i7300_process_error_global(mci); - i7300_process_fbd_error(mci); -}; - -/** - * i7300_clear_error() - Clears the error registers - * @mci: struct mem_ctl_info pointer - */ -static void i7300_clear_error(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt = mci->pvt_info; - u32 value; - /* - * All error values are RWC - we need to read and write 1 to the - * bit that we want to cleanup - */ - - /* Clear global error registers */ - pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_HI, &value); - pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_HI, value); - - pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_LO, &value); - pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, - FERR_GLOBAL_LO, value); - - /* Clear FBD error registers */ - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_FAT_FBD, &value); - pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_FAT_FBD, value); - - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_NF_FBD, &value); - pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - FERR_NF_FBD, value); -} - -/** - * i7300_enable_error_reporting() - Enable the memory reporting logic at the - * hardware - * @mci: struct mem_ctl_info pointer - */ -static void i7300_enable_error_reporting(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt = mci->pvt_info; - u32 fbd_error_mask; - - /* Read the FBD Error Mask Register */ - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - EMASK_FBD, &fbd_error_mask); - - /* Enable with a '0' */ - fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); - - pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, - EMASK_FBD, fbd_error_mask); -} - -/************************************************ - * i7300 Functions related to memory enumberation - ************************************************/ - -/** - * decode_mtr() - Decodes the MTR descriptor, filling the edac structs - * @pvt: pointer to the private data struct used by i7300 driver - * @slot: DIMM slot (0 to 7) - * @ch: Channel number within the branch (0 or 1) - * @branch: Branch number (0 or 1) - * @dinfo: Pointer to DIMM info where dimm size is stored - * @p_csrow: Pointer to the struct csrow_info that corresponds to that element - */ -static int decode_mtr(struct i7300_pvt *pvt, - int slot, int ch, int branch, - struct i7300_dimm_info *dinfo, - struct csrow_info *p_csrow, - u32 *nr_pages) -{ - int mtr, ans, addrBits, channel; - - channel = to_channel(ch, branch); - - mtr = pvt->mtr[slot][branch]; - ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0; - - debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n", - slot, channel, - ans ? "Present" : "NOT Present"); - - /* Determine if there is a DIMM present in this DIMM slot */ - if (!ans) - return 0; - - /* Start with the number of bits for a Bank - * on the DRAM */ - addrBits = MTR_DRAM_BANKS_ADDR_BITS; - /* Add thenumber of ROW bits */ - addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); - /* add the number of COLUMN bits */ - addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); - /* add the number of RANK bits */ - addrBits += MTR_DIMM_RANKS(mtr); - - addrBits += 6; /* add 64 bits per DIMM */ - addrBits -= 20; /* divide by 2^^20 */ - addrBits -= 3; /* 8 bits per bytes */ - - dinfo->megabytes = 1 << addrBits; - *nr_pages = dinfo->megabytes << 8; - - debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); - - debugf2("\t\tELECTRICAL THROTTLING is %s\n", - MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); - - debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); - debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single"); - debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); - debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); - debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes); - - p_csrow->grain = 8; - p_csrow->mtype = MEM_FB_DDR2; - p_csrow->csrow_idx = slot; - p_csrow->page_mask = 0; - - /* - * The type of error detection actually depends of the - * mode of operation. When it is just one single memory chip, at - * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code. - * In normal or mirrored mode, it uses Lockstep mode, - * with the possibility of using an extended algorithm for x8 memories - * See datasheet Sections 7.3.6 to 7.3.8 - */ - - if (IS_SINGLE_MODE(pvt->mc_settings_a)) { - p_csrow->edac_mode = EDAC_SECDED; - debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n"); - } else { - debugf2("\t\tECC code is on Lockstep mode\n"); - if (MTR_DRAM_WIDTH(mtr) == 8) - p_csrow->edac_mode = EDAC_S8ECD8ED; - else - p_csrow->edac_mode = EDAC_S4ECD4ED; - } - - /* ask what device type on this row */ - if (MTR_DRAM_WIDTH(mtr) == 8) { - debugf2("\t\tScrub algorithm for x8 is on %s mode\n", - IS_SCRBALGO_ENHANCED(pvt->mc_settings) ? - "enhanced" : "normal"); - - p_csrow->dtype = DEV_X8; - } else - p_csrow->dtype = DEV_X4; - - return mtr; -} - -/** - * print_dimm_size() - Prints dump of the memory organization - * @pvt: pointer to the private data struct used by i7300 driver - * - * Useful for debug. If debug is disabled, this routine do nothing - */ -static void print_dimm_size(struct i7300_pvt *pvt) -{ -#ifdef CONFIG_EDAC_DEBUG - struct i7300_dimm_info *dinfo; - char *p; - int space, n; - int channel, slot; - - space = PAGE_SIZE; - p = pvt->tmp_prt_buffer; - - n = snprintf(p, space, " "); - p += n; - space -= n; - for (channel = 0; channel < MAX_CHANNELS; channel++) { - n = snprintf(p, space, "channel %d | ", channel); - p += n; - space -= n; - } - debugf2("%s\n", pvt->tmp_prt_buffer); - p = pvt->tmp_prt_buffer; - space = PAGE_SIZE; - n = snprintf(p, space, "-------------------------------" - "------------------------------"); - p += n; - space -= n; - debugf2("%s\n", pvt->tmp_prt_buffer); - p = pvt->tmp_prt_buffer; - space = PAGE_SIZE; - - for (slot = 0; slot < MAX_SLOTS; slot++) { - n = snprintf(p, space, "csrow/SLOT %d ", slot); - p += n; - space -= n; - - for (channel = 0; channel < MAX_CHANNELS; channel++) { - dinfo = &pvt->dimm_info[slot][channel]; - n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); - p += n; - space -= n; - } - - debugf2("%s\n", pvt->tmp_prt_buffer); - p = pvt->tmp_prt_buffer; - space = PAGE_SIZE; - } - - n = snprintf(p, space, "-------------------------------" - "------------------------------"); - p += n; - space -= n; - debugf2("%s\n", pvt->tmp_prt_buffer); - p = pvt->tmp_prt_buffer; - space = PAGE_SIZE; -#endif -} - -/** - * i7300_init_csrows() - Initialize the 'csrows' table within - * the mci control structure with the - * addressing of memory. - * @mci: struct mem_ctl_info pointer - */ -static int i7300_init_csrows(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - struct i7300_dimm_info *dinfo; - struct csrow_info *p_csrow; - int rc = -ENODEV; - int mtr; - int ch, branch, slot, channel; - u32 last_page = 0, nr_pages; - - pvt = mci->pvt_info; - - debugf2("Memory Technology Registers:\n"); - - /* Get the AMB present registers for the four channels */ - for (branch = 0; branch < MAX_BRANCHES; branch++) { - /* Read and dump branch 0's MTRs */ - channel = to_channel(0, branch); - pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], - AMBPRESENT_0, - &pvt->ambpresent[channel]); - debugf2("\t\tAMB-present CH%d = 0x%x:\n", - channel, pvt->ambpresent[channel]); - - channel = to_channel(1, branch); - pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], - AMBPRESENT_1, - &pvt->ambpresent[channel]); - debugf2("\t\tAMB-present CH%d = 0x%x:\n", - channel, pvt->ambpresent[channel]); - } - - /* Get the set of MTR[0-7] regs by each branch */ - for (slot = 0; slot < MAX_SLOTS; slot++) { - int where = mtr_regs[slot]; - for (branch = 0; branch < MAX_BRANCHES; branch++) { - pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], - where, - &pvt->mtr[slot][branch]); - for (ch = 0; ch < MAX_BRANCHES; ch++) { - int channel = to_channel(ch, branch); - - dinfo = &pvt->dimm_info[slot][channel]; - p_csrow = &mci->csrows[slot]; - - mtr = decode_mtr(pvt, slot, ch, branch, - dinfo, p_csrow, &nr_pages); - /* if no DIMMS on this row, continue */ - if (!MTR_DIMMS_PRESENT(mtr)) - continue; - - /* Update per_csrow memory count */ - p_csrow->nr_pages += nr_pages; - p_csrow->first_page = last_page; - last_page += nr_pages; - p_csrow->last_page = last_page; - - rc = 0; - } - } - } - - return rc; -} - -/** - * decode_mir() - Decodes Memory Interleave Register (MIR) info - * @int mir_no: number of the MIR register to decode - * @mir: array with the MIR data cached on the driver - */ -static void decode_mir(int mir_no, u16 mir[MAX_MIR]) -{ - if (mir[mir_no] & 3) - debugf2("MIR%d: limit= 0x%x Branch(es) that participate:" - " %s %s\n", - mir_no, - (mir[mir_no] >> 4) & 0xfff, - (mir[mir_no] & 1) ? "B0" : "", - (mir[mir_no] & 2) ? "B1" : ""); -} - -/** - * i7300_get_mc_regs() - Get the contents of the MC enumeration registers - * @mci: struct mem_ctl_info pointer - * - * Data read is cached internally for its usage when needed - */ -static int i7300_get_mc_regs(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - u32 actual_tolm; - int i, rc; - - pvt = mci->pvt_info; - - pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE, - (u32 *) &pvt->ambase); - - debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase); - - /* Get the Branch Map regs */ - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm); - pvt->tolm >>= 12; - debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, - pvt->tolm); - - actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); - debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n", - actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); - - /* Get memory controller settings */ - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS, - &pvt->mc_settings); - pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A, - &pvt->mc_settings_a); - - if (IS_SINGLE_MODE(pvt->mc_settings_a)) - debugf0("Memory controller operating on single mode\n"); - else - debugf0("Memory controller operating on %s mode\n", - IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored"); - - debugf0("Error detection is %s\n", - IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); - debugf0("Retry is %s\n", - IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); - - /* Get Memory Interleave Range registers */ - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0, - &pvt->mir[0]); - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1, - &pvt->mir[1]); - pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2, - &pvt->mir[2]); - - /* Decode the MIR regs */ - for (i = 0; i < MAX_MIR; i++) - decode_mir(i, pvt->mir); - - rc = i7300_init_csrows(mci); - if (rc < 0) - return rc; - - /* Go and determine the size of each DIMM and place in an - * orderly matrix */ - print_dimm_size(pvt); - - return 0; -} - -/************************************************* - * i7300 Functions related to device probe/release - *************************************************/ - -/** - * i7300_put_devices() - Release the PCI devices - * @mci: struct mem_ctl_info pointer - */ -static void i7300_put_devices(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - int branch; - - pvt = mci->pvt_info; - - /* Decrement usage count for devices */ - for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++) - pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]); - pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs); - pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); -} - -/** - * i7300_get_devices() - Find and perform 'get' operation on the MCH's - * device/functions we want to reference for this driver - * @mci: struct mem_ctl_info pointer - * - * Access and prepare the several devices for usage: - * I7300 devices used by this driver: - * Device 16, functions 0,1 and 2: PCI_DEVICE_ID_INTEL_I7300_MCH_ERR - * Device 21 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 - * Device 22 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 - */ -static int __devinit i7300_get_devices(struct mem_ctl_info *mci) -{ - struct i7300_pvt *pvt; - struct pci_dev *pdev; - - pvt = mci->pvt_info; - - /* Attempt to 'get' the MCH register we want */ - pdev = NULL; - while (!pvt->pci_dev_16_1_fsb_addr_map || - !pvt->pci_dev_16_2_fsb_err_regs) { - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); - if (!pdev) { - /* End of list, leave */ - i7300_printk(KERN_ERR, - "'system address,Process Bus' " - "device not found:" - "vendor 0x%x device 0x%x ERR funcs " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); - goto error; - } - - /* Store device 16 funcs 1 and 2 */ - switch (PCI_FUNC(pdev->devfn)) { - case 1: - pvt->pci_dev_16_1_fsb_addr_map = pdev; - break; - case 2: - pvt->pci_dev_16_2_fsb_err_regs = pdev; - break; - } - } - - debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", - pci_name(pvt->pci_dev_16_0_fsb_ctlr), - pvt->pci_dev_16_0_fsb_ctlr->vendor, - pvt->pci_dev_16_0_fsb_ctlr->device); - debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", - pci_name(pvt->pci_dev_16_1_fsb_addr_map), - pvt->pci_dev_16_1_fsb_addr_map->vendor, - pvt->pci_dev_16_1_fsb_addr_map->device); - debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", - pci_name(pvt->pci_dev_16_2_fsb_err_regs), - pvt->pci_dev_16_2_fsb_err_regs->vendor, - pvt->pci_dev_16_2_fsb_err_regs->device); - - pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_FB0, - NULL); - if (!pvt->pci_dev_2x_0_fbd_branch[0]) { - i7300_printk(KERN_ERR, - "MC: 'BRANCH 0' device not found:" - "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0); - goto error; - } - - pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_FB1, - NULL); - if (!pvt->pci_dev_2x_0_fbd_branch[1]) { - i7300_printk(KERN_ERR, - "MC: 'BRANCH 1' device not found:" - "vendor 0x%x device 0x%x Func 0 " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_FB1); - goto error; - } - - return 0; - -error: - i7300_put_devices(mci); - return -ENODEV; -} - -/** - * i7300_init_one() - Probe for one instance of the device - * @pdev: struct pci_dev pointer - * @id: struct pci_device_id pointer - currently unused - */ -static int __devinit i7300_init_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct mem_ctl_info *mci; - struct i7300_pvt *pvt; - int num_channels; - int num_dimms_per_channel; - int num_csrows; - int rc; - - /* wake up device */ - rc = pci_enable_device(pdev); - if (rc == -EIO) - return rc; - - debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", - __func__, - pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - /* We only are looking for func 0 of the set */ - if (PCI_FUNC(pdev->devfn) != 0) - return -ENODEV; - - /* As we don't have a motherboard identification routine to determine - * actual number of slots/dimms per channel, we thus utilize the - * resource as specified by the chipset. Thus, we might have - * have more DIMMs per channel than actually on the mobo, but this - * allows the driver to support upto the chipset max, without - * some fancy mobo determination. - */ - num_dimms_per_channel = MAX_SLOTS; - num_channels = MAX_CHANNELS; - num_csrows = MAX_SLOTS * MAX_CHANNELS; - - debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", - __func__, num_channels, num_dimms_per_channel, num_csrows); - - /* allocate a new MC control structure */ - mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - - if (mci == NULL) - return -ENOMEM; - - debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - - mci->dev = &pdev->dev; /* record ptr to the generic device */ - - pvt = mci->pvt_info; - pvt->pci_dev_16_0_fsb_ctlr = pdev; /* Record this device in our private */ - - pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!pvt->tmp_prt_buffer) { - edac_mc_free(mci); - return -ENOMEM; - } - - /* 'get' the pci devices we want to reserve for our use */ - if (i7300_get_devices(mci)) - goto fail0; - - mci->mc_idx = 0; - mci->mtype_cap = MEM_FLAG_FB_DDR2; - mci->edac_ctl_cap = EDAC_FLAG_NONE; - mci->edac_cap = EDAC_FLAG_NONE; - mci->mod_name = "i7300_edac.c"; - mci->mod_ver = I7300_REVISION; - mci->ctl_name = i7300_devs[0].ctl_name; - mci->dev_name = pci_name(pdev); - mci->ctl_page_to_phys = NULL; - - /* Set the function pointer to an actual operation function */ - mci->edac_check = i7300_check_error; - - /* initialize the MC control structure 'csrows' table - * with the mapping and control information */ - if (i7300_get_mc_regs(mci)) { - debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" - " because i7300_init_csrows() returned nonzero " - "value\n"); - mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ - } else { - debugf1("MC: Enable error reporting now\n"); - i7300_enable_error_reporting(mci); - } - - /* add this new MC control structure to EDAC's list of MCs */ - if (edac_mc_add_mc(mci)) { - debugf0("MC: " __FILE__ - ": %s(): failed edac_mc_add_mc()\n", __func__); - /* FIXME: perhaps some code should go here that disables error - * reporting if we just enabled it - */ - goto fail1; - } - - i7300_clear_error(mci); - - /* allocating generic PCI control info */ - i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (!i7300_pci) { - printk(KERN_WARNING - "%s(): Unable to create PCI control\n", - __func__); - printk(KERN_WARNING - "%s(): PCI error report via EDAC not setup\n", - __func__); - } - - return 0; - - /* Error exit unwinding stack */ -fail1: - - i7300_put_devices(mci); - -fail0: - kfree(pvt->tmp_prt_buffer); - edac_mc_free(mci); - return -ENODEV; -} - -/** - * i7300_remove_one() - Remove the driver - * @pdev: struct pci_dev pointer - */ -static void __devexit i7300_remove_one(struct pci_dev *pdev) -{ - struct mem_ctl_info *mci; - char *tmp; - - debugf0(__FILE__ ": %s()\n", __func__); - - if (i7300_pci) - edac_pci_release_generic_ctl(i7300_pci); - - mci = edac_mc_del_mc(&pdev->dev); - if (!mci) - return; - - tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer; - - /* retrieve references to resources, and free those resources */ - i7300_put_devices(mci); - - kfree(tmp); - edac_mc_free(mci); -} - -/* - * pci_device_id: table for which devices we are looking for - * - * Has only 8086:360c PCI ID - */ -static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, - {0,} /* 0 terminated list. */ -}; - -MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); - -/* - * i7300_driver: pci_driver structure for this module - */ -static struct pci_driver i7300_driver = { - .name = "i7300_edac", - .probe = i7300_init_one, - .remove = __devexit_p(i7300_remove_one), - .id_table = i7300_pci_tbl, -}; - -/** - * i7300_init() - Registers the driver - */ -static int __init i7300_init(void) -{ - int pci_rc; - - debugf2("MC: " __FILE__ ": %s()\n", __func__); - - /* Ensure that the OPSTATE is set correctly for POLL or NMI */ - opstate_init(); - - pci_rc = pci_register_driver(&i7300_driver); - - return (pci_rc < 0) ? pci_rc : 0; -} - -/** - * i7300_init() - Unregisters the driver - */ -static void __exit i7300_exit(void) -{ - debugf2("MC: " __FILE__ ": %s()\n", __func__); - pci_unregister_driver(&i7300_driver); -} - -module_init(i7300_init); -module_exit(i7300_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " - I7300_REVISION); - -module_param(edac_op_state, int, 0444); -MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/trunk/drivers/edac/i82443bxgx_edac.c b/trunk/drivers/edac/i82443bxgx_edac.c index 678405ab04e4..a2fa1feed724 100644 --- a/trunk/drivers/edac/i82443bxgx_edac.c +++ b/trunk/drivers/edac/i82443bxgx_edac.c @@ -12,7 +12,7 @@ * 440GX fix by Jason Uhlenkott . * * Written with reference to 82443BX Host Bridge Datasheet: - * http://download.intel.com/design/chipsets/datashts/29063301.pdf + * http://www.intel.com/design/chipsets/440/documentation.htm * references to this document given in []. * * This module doesn't support the 440LX, but it may be possible to diff --git a/trunk/drivers/firmware/Kconfig b/trunk/drivers/firmware/Kconfig index e8b6a13515bd..88a3ae6cd023 100644 --- a/trunk/drivers/firmware/Kconfig +++ b/trunk/drivers/firmware/Kconfig @@ -74,8 +74,7 @@ config EFI_PCDP You must also enable the appropriate drivers (serial, VGA, etc.) - See DIG64_HCDPv20_042804.pdf available from - + See config DELL_RBU tristate "BIOS update support for DELL systems via sysfs" diff --git a/trunk/drivers/firmware/edd.c b/trunk/drivers/firmware/edd.c index 96c25d93eed1..f287fe79edc4 100644 --- a/trunk/drivers/firmware/edd.c +++ b/trunk/drivers/firmware/edd.c @@ -15,7 +15,7 @@ * made in setup.S, copied to safe structures in setup.c, * and presents it in sysfs. * - * Please see http://linux.dell.com/edd/results.html for + * Please see http://linux.dell.com/edd30/results.html for * the list of BIOSs which have been reported to implement EDD. * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/drivers/firmware/pcdp.h b/trunk/drivers/firmware/pcdp.h index e5530608e00d..ce910d68bd19 100644 --- a/trunk/drivers/firmware/pcdp.h +++ b/trunk/drivers/firmware/pcdp.h @@ -1,8 +1,8 @@ /* * Definitions for PCDP-defined console devices * - * For DIG64_HCDPv10a_01.pdf and DIG64_PCDPv20.pdf (v1.0a and v2.0 resp.), - * please see + * v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf + * v2.0: http://www.dig64.org/specifications/DIG64_PCDPv20.pdf * * (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P. * Khalid Aziz diff --git a/trunk/drivers/gpu/drm/drm_modes.c b/trunk/drivers/gpu/drm/drm_modes.c index 58e65f92c232..949326d2a8e5 100644 --- a/trunk/drivers/gpu/drm/drm_modes.c +++ b/trunk/drivers/gpu/drm/drm_modes.c @@ -76,7 +76,7 @@ EXPORT_SYMBOL(drm_mode_debug_printmodeline); * according to the hdisplay, vdisplay, vrefresh. * It is based from the VESA(TM) Coordinated Video Timing Generator by * Graham Loveridge April 9, 2003 available at - * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls + * http://www.vesa.org/public/CVT/CVTd6r1.xls * * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. * What I have done is to translate it by using integer calculation. diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_i2c.h b/trunk/drivers/gpu/drm/nouveau/nouveau_i2c.h index cfe7c8426d1d..f71cb32f7571 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -24,6 +24,7 @@ #define __NOUVEAU_I2C_H__ #include +#include #include #include "drm_dp_helper.h" diff --git a/trunk/drivers/gpu/drm/radeon/radeon_cs.c b/trunk/drivers/gpu/drm/radeon/radeon_cs.c index 6d64a2705f12..fcc79b5d22d1 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_cs.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_cs.c @@ -268,7 +268,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } r = radeon_ib_schedule(rdev, parser.ib); if (r) { - DRM_ERROR("Failed to schedule IB !\n"); + DRM_ERROR("Faild to schedule IB !\n"); } radeon_cs_parser_fini(&parser, r); mutex_unlock(&rdev->cs_mutex); diff --git a/trunk/drivers/gpu/drm/radeon/radeon_mode.h b/trunk/drivers/gpu/drm/radeon/radeon_mode.h index 454c1dc7ea45..17a6602b5885 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_mode.h +++ b/trunk/drivers/gpu/drm/radeon/radeon_mode.h @@ -36,6 +36,7 @@ #include #include #include +#include #include struct radeon_bo; diff --git a/trunk/drivers/gpu/drm/radeon/radeon_ttm.c b/trunk/drivers/gpu/drm/radeon/radeon_ttm.c index a823d8fe54c2..84c53e41a88f 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_ttm.c @@ -631,7 +631,7 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma) return drm_mmap(filp, vma); } - file_priv = filp->private_data; + file_priv = (struct drm_file *)filp->private_data; rdev = file_priv->minor->dev->dev_private; if (rdev == NULL) { return -EINVAL; diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 635c0ffee7fe..0fe31766e4cf 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -545,7 +545,7 @@ int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma) struct drm_file *file_priv; struct vmw_private *dev_priv; - file_priv = filp->private_data; + file_priv = (struct drm_file *)filp->private_data; dev_priv = vmw_priv(file_priv->minor->dev); if (vma->vm_pgoff != (dev_priv->mmio_start >> PAGE_SHIFT) || diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index 1e8eedd901e0..83123287c60c 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -39,7 +39,7 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) return drm_mmap(filp, vma); } - file_priv = filp->private_data; + file_priv = (struct drm_file *)filp->private_data; dev_priv = vmw_priv(file_priv->minor->dev); return ttm_bo_mmap(filp, vma, &dev_priv->bdev); } diff --git a/trunk/drivers/hid/Kconfig b/trunk/drivers/hid/Kconfig index 3052e2969ad0..6369ba7f96f8 100644 --- a/trunk/drivers/hid/Kconfig +++ b/trunk/drivers/hid/Kconfig @@ -56,20 +56,20 @@ menu "Special HID drivers" depends on HID config HID_3M_PCT - tristate "3M PCT touchscreen" + tristate "3M PCT" depends on USB_HID ---help--- Support for 3M PCT touch screens. config HID_A4TECH - tristate "A4 tech mice" if EMBEDDED + tristate "A4 tech" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for A4 tech X5 and WOP-35 / Trust 450L mice. config HID_ACRUX_FF - tristate "ACRUX force feedback" + tristate "ACRUX force feedback support" depends on USB_HID select INPUT_FF_MEMLESS ---help--- @@ -77,7 +77,7 @@ config HID_ACRUX_FF game controllers. config HID_APPLE - tristate "Apple {i,Power,Mac}Books" if EMBEDDED + tristate "Apple" if EMBEDDED depends on (USB_HID || BT_HIDP) default !EMBEDDED ---help--- @@ -88,7 +88,7 @@ config HID_APPLE MacBooks, MacBook Pros and Apple Aluminum. config HID_BELKIN - tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED + tristate "Belkin" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- @@ -101,14 +101,14 @@ config HID_CANDO Support for Cando dual touch panel. config HID_CHERRY - tristate "Cherry Cymotion keyboard" if EMBEDDED + tristate "Cherry" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Cherry Cymotion keyboard. config HID_CHICONY - tristate "Chicony Tactical pad" if EMBEDDED + tristate "Chicony" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- @@ -130,20 +130,20 @@ config HID_PRODIKEYS and some additional multimedia keys. config HID_CYPRESS - tristate "Cypress mouse and barcode readers" if EMBEDDED + tristate "Cypress" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for cypress mouse and barcode readers. config HID_DRAGONRISE - tristate "DragonRise Inc. game controller" + tristate "DragonRise Inc. support" depends on USB_HID ---help--- Say Y here if you have DragonRise Inc.game controllers. config DRAGONRISE_FF - bool "DragonRise Inc. force feedback" + bool "DragonRise Inc. force feedback support" depends on HID_DRAGONRISE select INPUT_FF_MEMLESS ---help--- @@ -157,58 +157,46 @@ config HID_EGALAX Support for the eGalax dual-touch panel. config HID_ELECOM - tristate "ELECOM BM084 bluetooth mouse" + tristate "ELECOM" depends on BT_HIDP ---help--- Support for the ELECOM BM084 (bluetooth mouse). config HID_EZKEY - tristate "Ezkey BTC 8193 keyboard" if EMBEDDED + tristate "Ezkey" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Ezkey BTC 8193 keyboard. config HID_KYE - tristate "Kye/Genius Ergo Mouse" if EMBEDDED + tristate "Kye" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Kye/Genius Ergo Mouse. -config HID_UCLOGIC - tristate "UC-Logic" - depends on USB_HID - ---help--- - Support for UC-Logic tablets. - -config HID_WALTOP - tristate "Waltop" - depends on USB_HID - ---help--- - Support for Waltop tablets. - config HID_GYRATION - tristate "Gyration remote control" + tristate "Gyration" depends on USB_HID ---help--- Support for Gyration remote control. config HID_TWINHAN - tristate "Twinhan IR remote control" + tristate "Twinhan" depends on USB_HID ---help--- Support for Twinhan IR remote control. config HID_KENSINGTON - tristate "Kensington Slimblade Trackball" if EMBEDDED + tristate "Kensington" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Kensington Slimblade Trackball. config HID_LOGITECH - tristate "Logitech devices" if EMBEDDED + tristate "Logitech" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- @@ -232,12 +220,12 @@ config LOGITECH_FF force feedback. config LOGIRUMBLEPAD2_FF - bool "Logitech RumblePad/Rumblepad 2 force feedback support" + bool "Logitech Rumblepad 2 force feedback support" depends on HID_LOGITECH select INPUT_FF_MEMLESS help Say Y here if you want to enable force feedback support for Logitech - RumblePad and Rumblepad 2 devices. + Rumblepad 2 devices. config LOGIG940_FF bool "Logitech Flight System G940 force feedback support" @@ -247,14 +235,6 @@ config LOGIG940_FF Say Y here if you want to enable force feedback support for Logitech Flight System G940 devices. -config LOGIWII_FF - bool "Logitech Speed Force Wireless force feedback support" - depends on HID_LOGITECH - select INPUT_FF_MEMLESS - help - Say Y here if you want to enable force feedback support for Logitech - Speed Force Wireless (Wii) devices. - config HID_MAGICMOUSE tristate "Apple MagicMouse multi-touch support" depends on BT_HIDP @@ -265,39 +245,39 @@ config HID_MAGICMOUSE Apple Wireless "Magic" Mouse. config HID_MICROSOFT - tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED + tristate "Microsoft" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Microsoft devices that are not fully compliant with HID standard. config HID_MOSART - tristate "MosArt dual-touch panels" + tristate "MosArt" depends on USB_HID ---help--- Support for MosArt dual-touch panels. config HID_MONTEREY - tristate "Monterey Genius KB29E keyboard" if EMBEDDED + tristate "Monterey" if EMBEDDED depends on USB_HID default !EMBEDDED ---help--- Support for Monterey Genius KB29E. config HID_NTRIG - tristate "N-Trig touch screen" + tristate "NTrig" depends on USB_HID ---help--- Support for N-Trig touch screen. config HID_ORTEK - tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad" + tristate "Ortek" depends on USB_HID ---help--- Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. config HID_PANTHERLORD - tristate "Pantherlord/GreenAsia game controller" + tristate "Pantherlord support" depends on USB_HID ---help--- Say Y here if you have a PantherLord/GreenAsia based game controller @@ -312,7 +292,7 @@ config PANTHERLORD_FF or adapter and want to enable force feedback support for it. config HID_PETALYNX - tristate "Petalynx Maxter remote control" + tristate "Petalynx" depends on USB_HID ---help--- Support for Petalynx Maxter remote control. @@ -376,7 +356,7 @@ config HID_PICOLCD_LEDS Provide access to PicoLCD's GPO pins via leds class. config HID_QUANTA - tristate "Quanta Optical Touch panels" + tristate "Quanta Optical Touch" depends on USB_HID ---help--- Support for Quanta Optical Touch dual-touch panels. @@ -396,39 +376,32 @@ config HID_ROCCAT_KONE ---help--- Support for Roccat Kone mouse. -config HID_ROCCAT_PYRA - tristate "Roccat Pyra mouse support" - depends on USB_HID - select HID_ROCCAT - ---help--- - Support for Roccat Pyra mouse. - config HID_SAMSUNG - tristate "Samsung InfraRed remote control or keyboards" + tristate "Samsung" depends on USB_HID ---help--- Support for Samsung InfraRed remote control or keyboards. config HID_SONY - tristate "Sony PS3 controller" + tristate "Sony" depends on USB_HID ---help--- Support for Sony PS3 controller. config HID_STANTUM - tristate "Stantum multitouch panel" + tristate "Stantum" depends on USB_HID ---help--- Support for Stantum multitouch panel. config HID_SUNPLUS - tristate "Sunplus wireless desktop" + tristate "Sunplus" depends on USB_HID ---help--- Support for Sunplus wireless desktop. config HID_GREENASIA - tristate "GreenAsia (Product ID 0x12) game controller support" + tristate "GreenAsia (Product ID 0x12) support" depends on USB_HID ---help--- Say Y here if you have a GreenAsia (Product ID 0x12) based game diff --git a/trunk/drivers/hid/Makefile b/trunk/drivers/hid/Makefile index c335605b9200..46f037f3df80 100644 --- a/trunk/drivers/hid/Makefile +++ b/trunk/drivers/hid/Makefile @@ -21,9 +21,6 @@ endif ifdef CONFIG_LOGIG940_FF hid-logitech-objs += hid-lg3ff.o endif -ifdef CONFIG_LOGIWII_FF - hid-logitech-objs += hid-lg4ff.o -endif obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o @@ -55,7 +52,6 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o -obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o @@ -65,11 +61,9 @@ obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o -obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_WACOM) += hid-wacom.o -obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/trunk/drivers/hid/hid-3m-pct.c b/trunk/drivers/hid/hid-3m-pct.c index 02d8cd3b1b1b..2a0d56b7a02b 100644 --- a/trunk/drivers/hid/hid-3m-pct.c +++ b/trunk/drivers/hid/hid-3m-pct.c @@ -2,8 +2,6 @@ * HID driver for 3M PCT multitouch panels * * Copyright (c) 2009-2010 Stephane Chatty - * Copyright (c) 2010 Henrik Rydberg - * Copyright (c) 2010 Canonical, Ltd. * */ @@ -26,26 +24,15 @@ MODULE_LICENSE("GPL"); #include "hid-ids.h" -#define MAX_SLOTS 60 -#define MAX_TRKID USHRT_MAX -#define MAX_EVENTS 360 - -/* estimated signal-to-noise ratios */ -#define SN_MOVE 2048 -#define SN_WIDTH 128 - struct mmm_finger { __s32 x, y, w, h; - __u16 id; - bool prev_touch; + __u8 rank; bool touch, valid; }; struct mmm_data { - struct mmm_finger f[MAX_SLOTS]; - __u16 id; - __u8 curid; - __u8 nexp, nreal; + struct mmm_finger f[10]; + __u8 curid, num; bool touch, valid; }; @@ -53,10 +40,6 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - int f1 = field->logical_minimum; - int f2 = field->logical_maximum; - int df = f2 - f1; - switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_BUTTON: @@ -67,20 +50,18 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_GD_X: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); - input_set_abs_params(hi->input, ABS_MT_POSITION_X, - f1, f2, df / SN_MOVE, 0); /* touchscreen emulation */ input_set_abs_params(hi->input, ABS_X, - f1, f2, df / SN_MOVE, 0); + field->logical_minimum, + field->logical_maximum, 0, 0); return 1; case HID_GD_Y: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); - input_set_abs_params(hi->input, ABS_MT_POSITION_Y, - f1, f2, df / SN_MOVE, 0); /* touchscreen emulation */ input_set_abs_params(hi->input, ABS_Y, - f1, f2, df / SN_MOVE, 0); + field->logical_minimum, + field->logical_maximum, 0, 0); return 1; } return 0; @@ -100,31 +81,21 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_TIPSWITCH: /* touchscreen emulation */ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - input_set_capability(hi->input, EV_KEY, BTN_TOUCH); return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); - input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, - f1, f2, df / SN_WIDTH, 0); return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); - input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, - f1, f2, df / SN_WIDTH, 0); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, - 0, 1, 0, 0); + 1, 1, 0, 0); return 1; case HID_DG_CONTACTID: - field->logical_maximum = MAX_TRKID; + field->logical_maximum = 59; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TRACKING_ID); - input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, - 0, MAX_TRKID, 0, 0); - if (!hi->input->mt) - input_mt_create_slots(hi->input, MAX_SLOTS); - input_set_events_per_packet(hi->input, MAX_EVENTS); return 1; } /* let hid-input decide for the others */ @@ -142,10 +113,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* tell hid-input to skip setup of these event types */ if (usage->type == EV_KEY || usage->type == EV_ABS) - set_bit(usage->type, hi->input->evbit); - return -1; + clear_bit(usage->code, *bit); + + return 0; } /* @@ -155,49 +126,70 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) { struct mmm_finger *oldest = 0; + bool pressed = false, released = false; int i; - for (i = 0; i < MAX_SLOTS; ++i) { + + /* + * we need to iterate on all fingers to decide if we have a press + * or a release event in our touchscreen emulation. + */ + for (i = 0; i < 10; ++i) { struct mmm_finger *f = &md->f[i]; if (!f->valid) { /* this finger is just placeholder data, ignore */ - continue; - } - input_mt_slot(input, i); - if (f->touch) { + } else if (f->touch) { /* this finger is on the screen */ int wide = (f->w > f->h); - /* divided by two to match visual scale of touch */ - int major = max(f->w, f->h) >> 1; - int minor = min(f->w, f->h) >> 1; - - if (!f->prev_touch) - f->id = md->id++; - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - /* touchscreen emulation: pick the oldest contact */ - if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1))) + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, + wide ? f->w : f->h); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, + wide ? f->h : f->w); + input_mt_sync(input); + /* + * touchscreen emulation: maintain the age rank + * of this finger, decide if we have a press + */ + if (f->rank == 0) { + f->rank = ++(md->num); + if (f->rank == 1) + pressed = true; + } + if (f->rank == 1) oldest = f; } else { /* this finger took off the screen */ - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1); + /* touchscreen emulation: maintain age rank of others */ + int j; + + for (j = 0; j < 10; ++j) { + struct mmm_finger *g = &md->f[j]; + if (g->rank > f->rank) { + g->rank--; + if (g->rank == 1) + oldest = g; + } + } + f->rank = 0; + --(md->num); + if (md->num == 0) + released = true; } - f->prev_touch = f->touch; f->valid = 0; } /* touchscreen emulation */ if (oldest) { - input_event(input, EV_KEY, BTN_TOUCH, 1); + if (pressed) + input_event(input, EV_KEY, BTN_TOUCH, 1); input_event(input, EV_ABS, ABS_X, oldest->x); input_event(input, EV_ABS, ABS_Y, oldest->y); - } else { + } else if (released) { input_event(input, EV_KEY, BTN_TOUCH, 0); } - input_sync(input); } /* @@ -231,12 +223,10 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field, md->f[md->curid].h = value; break; case HID_DG_CONTACTID: - value = clamp_val(value, 0, MAX_SLOTS - 1); if (md->valid) { md->curid = value; md->f[value].touch = md->touch; md->f[value].valid = 1; - md->nreal++; } break; case HID_GD_X: @@ -248,12 +238,7 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field, md->f[md->curid].y = value; break; case HID_DG_CONTACTCOUNT: - if (value) - md->nexp = value; - if (md->nreal >= md->nexp) { - mmm_filter_event(md, input); - md->nreal = 0; - } + mmm_filter_event(md, input); break; } } @@ -270,8 +255,6 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id) int ret; struct mmm_data *md; - hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; - md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL); if (!md) { dev_err(&hdev->dev, "cannot allocate 3M data\n"); diff --git a/trunk/drivers/hid/hid-a4tech.c b/trunk/drivers/hid/hid-a4tech.c index 1666c1684e79..3a2b223c1da4 100644 --- a/trunk/drivers/hid/hid-a4tech.c +++ b/trunk/drivers/hid/hid-a4tech.c @@ -133,8 +133,6 @@ static const struct hid_device_id a4_devices[] = { .driver_data = A4_2WHEEL_MOUSE_HACK_7 }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D), .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649), - .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, { } }; MODULE_DEVICE_TABLE(hid, a4_devices); diff --git a/trunk/drivers/hid/hid-apple.c b/trunk/drivers/hid/hid-apple.c index eaeca564a8d3..bba05d0a8980 100644 --- a/trunk/drivers/hid/hid-apple.c +++ b/trunk/drivers/hid/hid-apple.c @@ -246,18 +246,17 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field, /* * MacBook JIS keyboard has wrong logical maximum */ -static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { struct apple_sc *asc = hid_get_drvdata(hdev); - if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 && + if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) { dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report " "descriptor\n"); rdesc[53] = rdesc[59] = 0xe7; } - return rdesc; } static void apple_setup_input(struct input_dev *input) diff --git a/trunk/drivers/hid/hid-cherry.c b/trunk/drivers/hid/hid-cherry.c index e880086c2311..24663a8717b1 100644 --- a/trunk/drivers/hid/hid-cherry.c +++ b/trunk/drivers/hid/hid-cherry.c @@ -26,16 +26,15 @@ * Cherry Cymotion keyboard have an invalid HID report descriptor, * that needs fixing before we can parse it. */ -static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { dev_info(&hdev->dev, "fixing up Cherry Cymotion report " "descriptor\n"); rdesc[11] = rdesc[16] = 0xff; rdesc[12] = rdesc[17] = 0x03; } - return rdesc; } #define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ diff --git a/trunk/drivers/hid/hid-core.c b/trunk/drivers/hid/hid-core.c index 7832b6e2478b..3cb6632d4518 100644 --- a/trunk/drivers/hid/hid-core.c +++ b/trunk/drivers/hid/hid-core.c @@ -388,6 +388,12 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) __u32 data; unsigned n; + /* Local delimiter could have value 0, which allows size to be 0 */ + if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) { + dbg_hid("item data expected for local item\n"); + return -1; + } + data = item_udata(item); switch (item->tag) { @@ -645,7 +651,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start, }; if (device->driver->report_fixup) - start = device->driver->report_fixup(device, start, &size); + device->driver->report_fixup(device, start, size); device->rdesc = kmemdup(start, size, GFP_KERNEL); if (device->rdesc == NULL) @@ -1235,7 +1241,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE) { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, #endif @@ -1243,7 +1248,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, @@ -1323,7 +1327,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, @@ -1333,7 +1336,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, @@ -1369,15 +1371,12 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, @@ -1389,16 +1388,8 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, diff --git a/trunk/drivers/hid/hid-cypress.c b/trunk/drivers/hid/hid-cypress.c index 4cd0e2345991..998b6f443d7d 100644 --- a/trunk/drivers/hid/hid-cypress.c +++ b/trunk/drivers/hid/hid-cypress.c @@ -31,16 +31,16 @@ * Some USB barcode readers from cypress have usage min and usage max in * the wrong order */ -static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); unsigned int i; if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) - return rdesc; + return; - for (i = 0; i < *rsize - 4; i++) + for (i = 0; i < rsize - 4; i++) if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { __u8 tmp; @@ -50,7 +50,6 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[i + 3] = rdesc[i + 1]; rdesc[i + 1] = tmp; } - return rdesc; } static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi, diff --git a/trunk/drivers/hid/hid-debug.c b/trunk/drivers/hid/hid-debug.c index 75c5e23d09d2..61a3e572224a 100644 --- a/trunk/drivers/hid/hid-debug.c +++ b/trunk/drivers/hid/hid-debug.c @@ -570,8 +570,6 @@ void hid_debug_event(struct hid_device *hdev, char *buf) buf[i]; list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; } - - wake_up_interruptible(&hdev->debug_wait); } EXPORT_SYMBOL_GPL(hid_debug_event); diff --git a/trunk/drivers/hid/hid-egalax.c b/trunk/drivers/hid/hid-egalax.c index 54b017ad258d..8ca7f65cf2f8 100644 --- a/trunk/drivers/hid/hid-egalax.c +++ b/trunk/drivers/hid/hid-egalax.c @@ -31,7 +31,7 @@ struct egalax_data { bool first; /* is this the first finger in the frame? */ bool valid; /* valid finger data, or just placeholder? */ bool activity; /* at least one active finger previously? */ - __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */ + __u16 lastx, lasty; /* latest valid (x, y) in the frame */ }; static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -79,10 +79,6 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_TIPPRESSURE: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_PRESSURE, - field->logical_minimum, - field->logical_maximum, 0, 0); return 1; } return 0; @@ -113,8 +109,8 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) if (td->valid) { /* emit multitouch events */ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); - input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3); + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); input_mt_sync(input); @@ -125,7 +121,6 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) */ td->lastx = td->x; td->lasty = td->y; - td->lastz = td->z; } /* @@ -134,9 +129,8 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) * the oldest on the panel, the one we want for single touch */ if (!td->first && td->activity) { - input_event(input, EV_ABS, ABS_X, td->lastx >> 3); - input_event(input, EV_ABS, ABS_Y, td->lasty >> 3); - input_event(input, EV_ABS, ABS_PRESSURE, td->lastz); + input_event(input, EV_ABS, ABS_X, td->lastx); + input_event(input, EV_ABS, ABS_Y, td->lasty); } if (!td->valid) { diff --git a/trunk/drivers/hid/hid-elecom.c b/trunk/drivers/hid/hid-elecom.c index 6e31f305397d..7a40878f46b4 100644 --- a/trunk/drivers/hid/hid-elecom.c +++ b/trunk/drivers/hid/hid-elecom.c @@ -20,15 +20,14 @@ #include "hid-ids.h" -static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { + if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { dev_info(&hdev->dev, "Fixing up Elecom BM084 " "report descriptor.\n"); rdesc[47] = 0x00; } - return rdesc; } static const struct hid_device_id elecom_devices[] = { diff --git a/trunk/drivers/hid/hid-ids.h b/trunk/drivers/hid/hid-ids.h index 3ee999d33004..855aa8e355f4 100644 --- a/trunk/drivers/hid/hid-ids.h +++ b/trunk/drivers/hid/hid-ids.h @@ -25,7 +25,6 @@ #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_X5_005D 0x000a -#define USB_DEVICE_ID_A4TECH_RP_649 0x001a #define USB_VENDOR_ID_AASHIMA 0x06d6 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 @@ -64,7 +63,6 @@ #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d -#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 @@ -144,7 +142,6 @@ #define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051 #define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff #define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3 -#define USB_DEVICE_ID_CH_AXIS_295 0x001c #define USB_VENDOR_ID_CHERRY 0x046a #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 @@ -346,7 +343,6 @@ #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f -#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 @@ -358,7 +354,6 @@ #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 -#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_S510_RECEIVER 0xc50c #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 @@ -471,8 +466,6 @@ #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced -#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 -#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 @@ -492,12 +485,6 @@ #define USB_VENDOR_ID_STANTUM 0x1f87 #define USB_DEVICE_ID_MTP 0x0002 -#define USB_VENDOR_ID_STANTUM_STM 0x0483 -#define USB_DEVICE_ID_MTP_STM 0x3261 - -#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 -#define USB_DEVICE_ID_MTP_SITRONIX 0x5001 - #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab @@ -527,10 +514,8 @@ #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 -#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 +#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 #define USB_VENDOR_ID_VERNIER 0x08f7 #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 @@ -542,12 +527,6 @@ #define USB_VENDOR_ID_WACOM 0x056a #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 -#define USB_VENDOR_ID_WALTOP 0x172f -#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032 -#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH 0x0034 -#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501 -#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 - #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 diff --git a/trunk/drivers/hid/hid-input.c b/trunk/drivers/hid/hid-input.c index 834ef47b76d6..6c03dcc5760a 100644 --- a/trunk/drivers/hid/hid-input.c +++ b/trunk/drivers/hid/hid-input.c @@ -149,83 +149,6 @@ static int hidinput_setkeycode(struct input_dev *dev, } -/** - * hidinput_calc_abs_res - calculate an absolute axis resolution - * @field: the HID report field to calculate resolution for - * @code: axis code - * - * The formula is: - * (logical_maximum - logical_minimum) - * resolution = ---------------------------------------------------------- - * (physical_maximum - physical_minimum) * 10 ^ unit_exponent - * - * as seen in the HID specification v1.11 6.2.2.7 Global Items. - * - * Only exponent 1 length units are processed. Centimeters are converted to - * inches. Degrees are converted to radians. - */ -static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) -{ - __s32 unit_exponent = field->unit_exponent; - __s32 logical_extents = field->logical_maximum - - field->logical_minimum; - __s32 physical_extents = field->physical_maximum - - field->physical_minimum; - __s32 prev; - - /* Check if the extents are sane */ - if (logical_extents <= 0 || physical_extents <= 0) - return 0; - - /* - * Verify and convert units. - * See HID specification v1.11 6.2.2.7 Global Items for unit decoding - */ - if (code == ABS_X || code == ABS_Y || code == ABS_Z) { - if (field->unit == 0x11) { /* If centimeters */ - /* Convert to inches */ - prev = logical_extents; - logical_extents *= 254; - if (logical_extents < prev) - return 0; - unit_exponent += 2; - } else if (field->unit != 0x13) { /* If not inches */ - return 0; - } - } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) { - if (field->unit == 0x14) { /* If degrees */ - /* Convert to radians */ - prev = logical_extents; - logical_extents *= 573; - if (logical_extents < prev) - return 0; - unit_exponent += 1; - } else if (field->unit != 0x12) { /* If not radians */ - return 0; - } - } else { - return 0; - } - - /* Apply negative unit exponent */ - for (; unit_exponent < 0; unit_exponent++) { - prev = logical_extents; - logical_extents *= 10; - if (logical_extents < prev) - return 0; - } - /* Apply positive unit exponent */ - for (; unit_exponent > 0; unit_exponent--) { - prev = physical_extents; - physical_extents *= 10; - if (physical_extents < prev) - return 0; - } - - /* Calculate resolution */ - return logical_extents / physical_extents; -} - static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) { @@ -413,10 +336,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_key_clear(BTN_STYLUS); break; - case 0x46: /* TabletPick */ - map_key_clear(BTN_STYLUS2); - break; - default: goto unknown; } break; @@ -618,9 +537,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); else input_set_abs_params(input, usage->code, a, b, 0, 0); - input_abs_set_res(input, usage->code, - hidinput_calc_abs_res(field, usage->code)); - /* use a larger default input buffer for MT devices */ if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0) input_set_events_per_packet(input, 60); @@ -743,9 +659,6 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { struct hid_input *hidinput; - if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC) - return; - list_for_each_entry(hidinput, &hid->inputs, list) input_sync(hidinput->input); } diff --git a/trunk/drivers/hid/hid-kye.c b/trunk/drivers/hid/hid-kye.c index 817247ee006c..f8871712b7b5 100644 --- a/trunk/drivers/hid/hid-kye.c +++ b/trunk/drivers/hid/hid-kye.c @@ -23,10 +23,10 @@ * - report size 8 count 1 must be size 1 count 8 for button bitfield * - change the button usage range to 4-7 for the extra buttons */ -static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 74 && + if (rsize >= 74 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && @@ -40,7 +40,6 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[72] = 0x01; rdesc[74] = 0x08; } - return rdesc; } static const struct hid_device_id kye_devices[] = { diff --git a/trunk/drivers/hid/hid-lg.c b/trunk/drivers/hid/hid-lg.c index b629fba5a057..f6433d8050a9 100644 --- a/trunk/drivers/hid/hid-lg.c +++ b/trunk/drivers/hid/hid-lg.c @@ -7,7 +7,6 @@ * Copyright (c) 2006-2007 Jiri Kosina * Copyright (c) 2007 Paul Walmsley * Copyright (c) 2008 Jiri Slaby - * Copyright (c) 2010 Hendrik Iben */ /* @@ -20,9 +19,6 @@ #include #include #include -#include -#include -#include #include "hid-ids.h" #include "hid-lg.h" @@ -39,43 +35,31 @@ #define LG_FF2 0x400 #define LG_RDESC_REL_ABS 0x800 #define LG_FF3 0x1000 -#define LG_FF4 0x2000 /* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends * the original value of 0x28c of logical maximum to 0x104d */ -static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && + if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { dev_info(&hdev->dev, "fixing up Logitech keyboard report " "descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } - if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && + if ((quirks & LG_RDESC_REL_ABS) && rsize >= 50 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { dev_info(&hdev->dev, "fixing up rel/abs in Logitech " "report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } - if ((quirks & LG_FF4) && *rsize >= 101 && - rdesc[41] == 0x95 && rdesc[42] == 0x0B && - rdesc[47] == 0x05 && rdesc[48] == 0x09) { - dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless " - "button descriptor\n"); - rdesc[41] = 0x05; - rdesc[42] = 0x09; - rdesc[47] = 0x95; - rdesc[48] = 0x0B; - } - return rdesc; } #define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ @@ -301,33 +285,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - if (quirks & LG_FF4) { - unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); - - if (ret >= 0) { - /* insert a little delay of 10 jiffies ~ 40ms */ - wait_queue_head_t wait; - init_waitqueue_head (&wait); - wait_event_interruptible_timeout(wait, 0, 10); - - /* Select random Address */ - buf[1] = 0xB2; - get_random_bytes(&buf[2], 2); - - ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); - } - } - if (quirks & LG_FF) lgff_init(hdev); if (quirks & LG_FF2) lg2ff_init(hdev); if (quirks & LG_FF3) lg3ff_init(hdev); - if (quirks & LG_FF4) - lg4ff_init(hdev); return 0; err_free: @@ -362,8 +325,6 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), .driver_data = LG_NOGET | LG_FF }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD), - .driver_data = LG_FF2 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), @@ -378,8 +339,6 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), .driver_data = LG_FF }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), - .driver_data = LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), diff --git a/trunk/drivers/hid/hid-lg.h b/trunk/drivers/hid/hid-lg.h index b0100ba2ae0b..ce2ac8672624 100644 --- a/trunk/drivers/hid/hid-lg.h +++ b/trunk/drivers/hid/hid-lg.h @@ -19,10 +19,4 @@ int lg3ff_init(struct hid_device *hdev); static inline int lg3ff_init(struct hid_device *hdev) { return -1; } #endif -#ifdef CONFIG_LOGIWII_FF -int lg4ff_init(struct hid_device *hdev); -#else -static inline int lg4ff_init(struct hid_device *hdev) { return -1; } -#endif - #endif diff --git a/trunk/drivers/hid/hid-lg2ff.c b/trunk/drivers/hid/hid-lg2ff.c index 4258253c36b3..d888f1e6794f 100644 --- a/trunk/drivers/hid/hid-lg2ff.c +++ b/trunk/drivers/hid/hid-lg2ff.c @@ -1,5 +1,5 @@ /* - * Force feedback support for Logitech RumblePad and Rumblepad 2 + * Force feedback support for Logitech Rumblepad 2 * * Copyright (c) 2008 Anssi Hannula */ @@ -110,7 +110,7 @@ int lg2ff_init(struct hid_device *hid) usbhid_submit_report(hid, report, USB_DIR_OUT); - dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by " + dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by " "Anssi Hannula \n"); return 0; diff --git a/trunk/drivers/hid/hid-lg4ff.c b/trunk/drivers/hid/hid-lg4ff.c deleted file mode 100644 index 7eef5a2ce948..000000000000 --- a/trunk/drivers/hid/hid-lg4ff.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Force feedback support for Logitech Speed Force Wireless - * - * http://wiibrew.org/wiki/Logitech_USB_steering_wheel - * - * Copyright (c) 2010 Simon Wood - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include - -#include "usbhid/usbhid.h" -#include "hid-lg.h" - -struct lg4ff_device { - struct hid_report *report; -}; - -static const signed short ff4_wheel_ac[] = { - FF_CONSTANT, - FF_AUTOCENTER, - -1 -}; - -static int hid_lg4ff_play(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - int x; - -#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff - - switch (effect->type) { - case FF_CONSTANT: - x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ - CLAMP(x); - report->field[0]->value[0] = 0x11; /* Slot 1 */ - report->field[0]->value[1] = 0x10; - report->field[0]->value[2] = x; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x08; - report->field[0]->value[6] = 0x00; - dbg_hid("Autocenter, x=0x%02X\n", x); - - usbhid_submit_report(hid, report, USB_DIR_OUT); - break; - } - return 0; -} - -static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; - - *value++ = 0xfe; - *value++ = 0x0d; - *value++ = 0x07; - *value++ = 0x07; - *value++ = (magnitude >> 8) & 0xff; - *value++ = 0x00; - *value = 0x00; - - usbhid_submit_report(hid, report, USB_DIR_OUT); -} - - -int lg4ff_init(struct hid_device *hid) -{ - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; - struct hid_report *report; - struct hid_field *field; - const signed short *ff_bits = ff4_wheel_ac; - int error; - int i; - - /* Find the report to use */ - if (list_empty(report_list)) { - err_hid("No output report found"); - return -1; - } - - /* Check that the report looks ok */ - report = list_entry(report_list->next, struct hid_report, list); - if (!report) { - err_hid("NULL output report"); - return -1; - } - - field = report->field[0]; - if (!field) { - err_hid("NULL field"); - return -1; - } - - for (i = 0; ff_bits[i] >= 0; i++) - set_bit(ff_bits[i], dev->ffbit); - - error = input_ff_create_memless(dev, NULL, hid_lg4ff_play); - - if (error) - return error; - - if (test_bit(FF_AUTOCENTER, dev->ffbit)) - dev->ff->set_autocenter = hid_lg4ff_set_autocenter; - - dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by " - "Simon Wood \n"); - return 0; -} - diff --git a/trunk/drivers/hid/hid-magicmouse.c b/trunk/drivers/hid/hid-magicmouse.c index e6dc15171664..319b0e57ee41 100644 --- a/trunk/drivers/hid/hid-magicmouse.c +++ b/trunk/drivers/hid/hid-magicmouse.c @@ -2,7 +2,6 @@ * Apple "Magic" Wireless Mouse driver * * Copyright (c) 2010 Michael Poole - * Copyright (c) 2010 Chase Douglas */ /* @@ -54,9 +53,7 @@ static bool report_undeciphered; module_param(report_undeciphered, bool, 0644); MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); -#define TRACKPAD_REPORT_ID 0x28 -#define MOUSE_REPORT_ID 0x29 -#define DOUBLE_REPORT_ID 0xf7 +#define TOUCH_REPORT_ID 0x29 /* These definitions are not precise, but they're close enough. (Bits * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem * to be some kind of bit mask -- 0x20 may be a near-field reading, @@ -70,19 +67,15 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define SCROLL_ACCEL_DEFAULT 7 -/* Single touch emulation should only begin when no touches are currently down. - * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches - * are down and the touch providing for single touch emulation is lifted, - * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is - * occuring, single_touch_id corresponds with the tracking id of the touch used. - */ -#define NO_TOUCHES -1 -#define SINGLE_TOUCH_UP -2 - /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. * @quirks: Currently unused. + * @last_timestamp: Timestamp from most recent (18-bit) touch report + * (units of milliseconds over short windows, but seems to + * increase faster when there are no touches). + * @delta_time: 18-bit difference between the two most recent touch + * reports from the mouse. * @ntouches: Number of touches in most recent touch report. * @scroll_accel: Number of consecutive scroll motions. * @scroll_jiffies: Time of last scroll motion. @@ -93,6 +86,8 @@ struct magicmouse_sc { struct input_dev *input; unsigned long quirks; + int last_timestamp; + int delta_time; int ntouches; int scroll_accel; unsigned long scroll_jiffies; @@ -103,9 +98,9 @@ struct magicmouse_sc { short scroll_x; short scroll_y; u8 size; + u8 down; } touches[16]; int tracking_ids[16]; - int single_touch_id; }; static int magicmouse_firm_touch(struct magicmouse_sc *msc) @@ -171,35 +166,18 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) { struct input_dev *input = msc->input; - int id, x, y, size, orientation, touch_major, touch_minor, state, down; - - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { - id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf; - x = (tdata[1] << 28 | tdata[0] << 20) >> 20; - y = -((tdata[2] << 24 | tdata[1] << 16) >> 20); - size = tdata[5] & 0x3f; - orientation = (tdata[6] >> 2) - 32; - touch_major = tdata[3]; - touch_minor = tdata[4]; - state = tdata[7] & TOUCH_STATE_MASK; - down = state != TOUCH_STATE_NONE; - } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf; - x = (tdata[1] << 27 | tdata[0] << 19) >> 19; - y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19); - size = tdata[6] & 0x3f; - orientation = (tdata[7] >> 2) - 32; - touch_major = tdata[4]; - touch_minor = tdata[5]; - state = tdata[8] & TOUCH_STATE_MASK; - down = state != TOUCH_STATE_NONE; - } + __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24; + int misc = tdata[5] | tdata[6] << 8; + int id = (misc >> 6) & 15; + int x = x_y << 12 >> 20; + int y = -(x_y >> 20); + int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE; /* Store tracking ID and other fields. */ msc->tracking_ids[raw_id] = id; msc->touches[id].x = x; msc->touches[id].y = y; - msc->touches[id].size = size; + msc->touches[id].size = misc & 63; /* If requested, emulate a scroll wheel by detecting small * vertical touch motions. @@ -210,7 +188,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda int step_y = msc->touches[id].scroll_y - y; /* Calculate and apply the scroll motion. */ - switch (state) { + switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_x = x; msc->touches[id].scroll_y = y; @@ -244,28 +222,21 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda } } - if (down) { - msc->ntouches++; - if (msc->single_touch_id == NO_TOUCHES) - msc->single_touch_id = id; - } else if (msc->single_touch_id == id) - msc->single_touch_id = SINGLE_TOUCH_UP; - /* Generate the input events for this touch. */ if (report_touches && down) { + int orientation = (misc >> 10) - 32; + + msc->touches[id].down = 1; + input_report_abs(input, ABS_MT_TRACKING_ID, id); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2); - input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); + input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); input_report_abs(input, ABS_MT_ORIENTATION, orientation); input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - if (report_undeciphered) { - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) - input_event(input, EV_MSC, MSC_RAW, tdata[7]); - else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - input_event(input, EV_MSC, MSC_RAW, tdata[8]); - } + if (report_undeciphered) + input_event(input, EV_MSC, MSC_RAW, tdata[7]); input_mt_sync(input); } @@ -276,43 +247,39 @@ static int magicmouse_raw_event(struct hid_device *hdev, { struct magicmouse_sc *msc = hid_get_drvdata(hdev); struct input_dev *input = msc->input; - int x = 0, y = 0, ii, clicks = 0, npoints; + int x, y, ts, ii, clicks, last_up; switch (data[0]) { - case TRACKPAD_REPORT_ID: - /* Expect four bytes of prefix, and N*9 bytes of touch data. */ - if (size < 4 || ((size - 4) % 9) != 0) + case 0x10: + if (size != 6) return 0; - npoints = (size - 4) / 9; - msc->ntouches = 0; - for (ii = 0; ii < npoints; ii++) - magicmouse_emit_touch(msc, ii, data + ii * 9 + 4); - - /* We don't need an MT sync here because trackpad emits a - * BTN_TOUCH event in a new frame when all touches are released. - */ - if (msc->ntouches == 0) - msc->single_touch_id = NO_TOUCHES; - + x = (__s16)(data[2] | data[3] << 8); + y = (__s16)(data[4] | data[5] << 8); clicks = data[1]; - - /* The following bits provide a device specific timestamp. They - * are unused here. - * - * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10; - */ break; - case MOUSE_REPORT_ID: + case TOUCH_REPORT_ID: /* Expect six bytes of prefix, and N*8 bytes of touch data. */ if (size < 6 || ((size - 6) % 8) != 0) return 0; - npoints = (size - 6) / 8; - msc->ntouches = 0; - for (ii = 0; ii < npoints; ii++) + ts = data[3] >> 6 | data[4] << 2 | data[5] << 10; + msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff; + msc->last_timestamp = ts; + msc->ntouches = (size - 6) / 8; + for (ii = 0; ii < msc->ntouches; ii++) magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); - if (report_touches && msc->ntouches == 0) - input_mt_sync(input); + if (report_touches) { + last_up = 1; + for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) { + if (msc->touches[ii].down) { + last_up = 0; + msc->touches[ii].down = 0; + } + } + if (last_up) { + input_mt_sync(input); + } + } /* When emulating three-button mode, it is important * to have the current touch information before @@ -321,72 +288,68 @@ static int magicmouse_raw_event(struct hid_device *hdev, x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22; y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22; clicks = data[3]; - - /* The following bits provide a device specific timestamp. They - * are unused here. - * - * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10; - */ - break; - case DOUBLE_REPORT_ID: - /* Sometimes the trackpad sends two touch reports in one - * packet. - */ - magicmouse_raw_event(hdev, report, data + 2, data[1]); - magicmouse_raw_event(hdev, report, data + 2 + data[1], - size - 2 - data[1]); break; + case 0x20: /* Theoretically battery status (0-100), but I have + * never seen it -- maybe it is only upon request. + */ + case 0x60: /* Unknown, maybe laser on/off. */ + case 0x61: /* Laser reflection status change. + * data[1]: 0 = spotted, 1 = lost + */ default: return 0; } - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { - magicmouse_emit_buttons(msc, clicks & 3); - input_report_rel(input, REL_X, x); - input_report_rel(input, REL_Y, y); - } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - input_report_key(input, BTN_MOUSE, clicks & 1); - input_report_key(input, BTN_TOUCH, msc->ntouches > 0); - input_report_key(input, BTN_TOOL_FINGER, msc->ntouches == 1); - input_report_key(input, BTN_TOOL_DOUBLETAP, msc->ntouches == 2); - input_report_key(input, BTN_TOOL_TRIPLETAP, msc->ntouches == 3); - input_report_key(input, BTN_TOOL_QUADTAP, msc->ntouches == 4); - if (msc->single_touch_id >= 0) { - input_report_abs(input, ABS_X, - msc->touches[msc->single_touch_id].x); - input_report_abs(input, ABS_Y, - msc->touches[msc->single_touch_id].y); - } - } - + magicmouse_emit_buttons(msc, clicks & 3); + input_report_rel(input, REL_X, x); + input_report_rel(input, REL_Y, y); input_sync(input); return 1; } +static int magicmouse_input_open(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + return hid->ll_driver->open(hid); +} + +static void magicmouse_input_close(struct input_dev *dev) +{ + struct hid_device *hid = input_get_drvdata(dev); + + hid->ll_driver->close(hid); +} + static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) { - __set_bit(EV_KEY, input->evbit); + input_set_drvdata(input, hdev); + input->event = hdev->ll_driver->hidinput_input_event; + input->open = magicmouse_input_open; + input->close = magicmouse_input_close; + + input->name = hdev->name; + input->phys = hdev->phys; + input->uniq = hdev->uniq; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + input->dev.parent = hdev->dev.parent; - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { - __set_bit(BTN_LEFT, input->keybit); - __set_bit(BTN_RIGHT, input->keybit); - if (emulate_3button) - __set_bit(BTN_MIDDLE, input->keybit); - - __set_bit(EV_REL, input->evbit); - __set_bit(REL_X, input->relbit); - __set_bit(REL_Y, input->relbit); - if (emulate_scroll_wheel) { - __set_bit(REL_WHEEL, input->relbit); - __set_bit(REL_HWHEEL, input->relbit); - } - } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - __set_bit(BTN_MOUSE, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); - __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); - __set_bit(BTN_TOOL_QUADTAP, input->keybit); - __set_bit(BTN_TOUCH, input->keybit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); + __set_bit(BTN_RIGHT, input->keybit); + if (emulate_3button) + __set_bit(BTN_MIDDLE, input->keybit); + __set_bit(BTN_TOOL_FINGER, input->keybit); + + __set_bit(EV_REL, input->evbit); + __set_bit(REL_X, input->relbit); + __set_bit(REL_Y, input->relbit); + if (emulate_scroll_wheel) { + __set_bit(REL_WHEEL, input->relbit); + __set_bit(REL_HWHEEL, input->relbit); } if (report_touches) { @@ -396,26 +359,16 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0); input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0); - + input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358, + 4, 0); /* Note: Touch Y position from the device is inverted relative * to how pointer motion is reported (and relative to how USB * HID recommends the coordinates work). This driver keeps * the origin at the same position, and just uses the additive * inverse of the reported Y. */ - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { - input_set_abs_params(input, ABS_MT_POSITION_X, -1100, - 1358, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, - 2047, 4, 0); - } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0); - input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_X, -2909, - 3167, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, -2456, - 2565, 4, 0); - } + input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047, + 4, 0); } if (report_undeciphered) { @@ -424,22 +377,12 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h } } -static int magicmouse_input_mapping(struct hid_device *hdev, - struct hid_input *hi, struct hid_field *field, - struct hid_usage *usage, unsigned long **bit, int *max) -{ - struct magicmouse_sc *msc = hid_get_drvdata(hdev); - - if (!msc->input) - msc->input = hi->input; - - return 0; -} - static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { - __u8 feature[] = { 0xd7, 0x01 }; + __u8 feature_1[] = { 0xd7, 0x01 }; + __u8 feature_2[] = { 0xf8, 0x01, 0x32 }; + struct input_dev *input; struct magicmouse_sc *msc; struct hid_report *report; int ret; @@ -455,8 +398,6 @@ static int magicmouse_probe(struct hid_device *hdev, msc->quirks = id->driver_data; hid_set_drvdata(hdev, msc); - msc->single_touch_id = NO_TOUCHES; - ret = hid_parse(hdev); if (ret) { dev_err(&hdev->dev, "magicmouse hid parse failed\n"); @@ -469,22 +410,10 @@ static int magicmouse_probe(struct hid_device *hdev, goto err_free; } - /* We do this after hid-input is done parsing reports so that - * hid-input uses the most natural button and axis IDs. - */ - if (msc->input) - magicmouse_setup_input(msc->input, hdev); - - if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) - report = hid_register_report(hdev, HID_INPUT_REPORT, - MOUSE_REPORT_ID); - else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - report = hid_register_report(hdev, HID_INPUT_REPORT, - TRACKPAD_REPORT_ID); - report = hid_register_report(hdev, HID_INPUT_REPORT, - DOUBLE_REPORT_ID); - } + /* we are handling the input ourselves */ + hidinput_disconnect(hdev); + report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); ret = -ENOMEM; @@ -492,15 +421,39 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; - ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), + ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1), HID_FEATURE_REPORT); - if (ret != sizeof(feature)) { - dev_err(&hdev->dev, "unable to request touch data (%d)\n", + if (ret != sizeof(feature_1)) { + dev_err(&hdev->dev, "unable to request touch data (1:%d)\n", + ret); + goto err_stop_hw; + } + ret = hdev->hid_output_raw_report(hdev, feature_2, + sizeof(feature_2), HID_FEATURE_REPORT); + if (ret != sizeof(feature_2)) { + dev_err(&hdev->dev, "unable to request touch data (2:%d)\n", ret); goto err_stop_hw; } + input = input_allocate_device(); + if (!input) { + dev_err(&hdev->dev, "can't alloc input device\n"); + ret = -ENOMEM; + goto err_stop_hw; + } + magicmouse_setup_input(input, hdev); + + ret = input_register_device(input); + if (ret) { + dev_err(&hdev->dev, "input device registration failed\n"); + goto err_input; + } + msc->input = input; + return 0; +err_input: + input_free_device(input); err_stop_hw: hid_hw_stop(hdev); err_free: @@ -513,14 +466,13 @@ static void magicmouse_remove(struct hid_device *hdev) struct magicmouse_sc *msc = hid_get_drvdata(hdev); hid_hw_stop(hdev); + input_unregister_device(msc->input); kfree(msc); } static const struct hid_device_id magic_mice[] = { - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), + .driver_data = 0 }, { } }; MODULE_DEVICE_TABLE(hid, magic_mice); @@ -531,7 +483,6 @@ static struct hid_driver magicmouse_driver = { .probe = magicmouse_probe, .remove = magicmouse_remove, .raw_event = magicmouse_raw_event, - .input_mapping = magicmouse_input_mapping, }; static int __init magicmouse_init(void) diff --git a/trunk/drivers/hid/hid-microsoft.c b/trunk/drivers/hid/hid-microsoft.c index dc618c33d0a2..359cc447c6c6 100644 --- a/trunk/drivers/hid/hid-microsoft.c +++ b/trunk/drivers/hid/hid-microsoft.c @@ -33,19 +33,18 @@ * Microsoft Wireless Desktop Receiver (Model 1028) has * 'Usage Min/Max' where it ought to have 'Physical Min/Max' */ -static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && + if ((quirks & MS_RDESC) && rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver " "Model 1028 report descriptor\n"); rdesc[557] = 0x35; rdesc[559] = 0x45; } - return rdesc; } #define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ diff --git a/trunk/drivers/hid/hid-monterey.c b/trunk/drivers/hid/hid-monterey.c index c95c31e2d869..2cd05aa244b9 100644 --- a/trunk/drivers/hid/hid-monterey.c +++ b/trunk/drivers/hid/hid-monterey.c @@ -22,15 +22,14 @@ #include "hid-ids.h" -static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { + if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { dev_info(&hdev->dev, "fixing up button/consumer in HID report " "descriptor\n"); rdesc[30] = 0x0c; } - return rdesc; } #define mr_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ diff --git a/trunk/drivers/hid/hid-ntrig.c b/trunk/drivers/hid/hid-ntrig.c index 69169efa1e16..fb69b8c4953f 100644 --- a/trunk/drivers/hid/hid-ntrig.c +++ b/trunk/drivers/hid/hid-ntrig.c @@ -90,55 +90,6 @@ struct ntrig_data { }; -/* - * This function converts the 4 byte raw firmware code into - * a string containing 5 comma separated numbers. - */ -static int ntrig_version_string(unsigned char *raw, char *buf) -{ - __u8 a = (raw[1] & 0x0e) >> 1; - __u8 b = (raw[0] & 0x3c) >> 2; - __u8 c = ((raw[0] & 0x03) << 3) | ((raw[3] & 0xe0) >> 5); - __u8 d = ((raw[3] & 0x07) << 3) | ((raw[2] & 0xe0) >> 5); - __u8 e = raw[2] & 0x07; - - /* - * As yet unmapped bits: - * 0b11000000 0b11110001 0b00011000 0b00011000 - */ - - return sprintf(buf, "%u.%u.%u.%u.%u", a, b, c, d, e); -} - -static void ntrig_report_version(struct hid_device *hdev) -{ - int ret; - char buf[20]; - struct usb_device *usb_dev = hid_to_usb_dev(hdev); - unsigned char *data = kmalloc(8, GFP_KERNEL); - - if (!data) - goto err_free; - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | - USB_DIR_IN, - 0x30c, 1, data, 8, - USB_CTRL_SET_TIMEOUT); - - if (ret == 8) { - ret = ntrig_version_string(&data[2], buf); - - dev_info(&hdev->dev, - "Firmware version: %s (%02x%02x %02x%02x)\n", - buf, data[2], data[3], data[4], data[5]); - } - -err_free: - kfree(data); -} - static ssize_t show_phys_width(struct device *dev, struct device_attribute *attr, char *buf) @@ -426,8 +377,8 @@ static struct attribute_group ntrig_attribute_group = { */ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) { struct ntrig_data *nd = hid_get_drvdata(hdev); @@ -497,13 +448,13 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* width/height mapped on TouchMajor/TouchMinor/Orientation */ case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MAJOR); + EV_ABS, ABS_MT_TOUCH_MAJOR); return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MINOR); + EV_ABS, ABS_MT_TOUCH_MINOR); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, - 0, 1, 0, 0); + 0, 1, 0, 0); return 1; } return 0; @@ -517,8 +468,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, } static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) { /* No special mappings needed for the pen and single touch */ if (field->physical) @@ -538,7 +489,7 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, * and call input_mt_sync after each point if necessary */ static int ntrig_event (struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) + struct hid_usage *usage, __s32 value) { struct input_dev *input = field->hidinput->input; struct ntrig_data *nd = hid_get_drvdata(hid); @@ -897,8 +848,6 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) if (report) usbhid_submit_report(hdev, report, USB_DIR_OUT); - ntrig_report_version(hdev); - ret = sysfs_create_group(&hdev->dev.kobj, &ntrig_attribute_group); @@ -911,7 +860,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) static void ntrig_remove(struct hid_device *hdev) { sysfs_remove_group(&hdev->dev.kobj, - &ntrig_attribute_group); + &ntrig_attribute_group); hid_hw_stop(hdev); kfree(hid_get_drvdata(hdev)); } diff --git a/trunk/drivers/hid/hid-ortek.c b/trunk/drivers/hid/hid-ortek.c index 2e79716dca31..aa9a960f73a4 100644 --- a/trunk/drivers/hid/hid-ortek.c +++ b/trunk/drivers/hid/hid-ortek.c @@ -19,15 +19,14 @@ #include "hid-ids.h" -static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { + if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 " "report descriptor.\n"); rdesc[55] = 0x92; } - return rdesc; } static const struct hid_device_id ortek_devices[] = { diff --git a/trunk/drivers/hid/hid-petalynx.c b/trunk/drivers/hid/hid-petalynx.c index 308d6ae48a3e..500fbd0652dc 100644 --- a/trunk/drivers/hid/hid-petalynx.c +++ b/trunk/drivers/hid/hid-petalynx.c @@ -23,10 +23,10 @@ #include "hid-ids.h" /* Petalynx Maxter Remote has maximum for consumer page set too low */ -static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && + if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && rdesc[41] == 0x00 && rdesc[59] == 0x26 && rdesc[60] == 0xf9 && rdesc[61] == 0x00) { dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report " @@ -34,7 +34,6 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[60] = 0xfa; rdesc[40] = 0xfa; } - return rdesc; } #define pl_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ diff --git a/trunk/drivers/hid/hid-prodikeys.c b/trunk/drivers/hid/hid-prodikeys.c index 48eab84f53b5..845f428b8090 100644 --- a/trunk/drivers/hid/hid-prodikeys.c +++ b/trunk/drivers/hid/hid-prodikeys.c @@ -740,10 +740,10 @@ int pcmidi_snd_terminate(struct pcmidi_snd *pm) /* * PC-MIDI report descriptor for report id is wrong. */ -static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void pk_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize == 178 && + if (rsize == 178 && rdesc[111] == 0x06 && rdesc[112] == 0x00 && rdesc[113] == 0xff) { dev_info(&hdev->dev, "fixing up pc-midi keyboard report " @@ -751,7 +751,6 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[144] = 0x18; /* report 4: was 0x10 report count */ } - return rdesc; } static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi, diff --git a/trunk/drivers/hid/hid-roccat-pyra.c b/trunk/drivers/hid/hid-roccat-pyra.c deleted file mode 100644 index 9bf23047892a..000000000000 --- a/trunk/drivers/hid/hid-roccat-pyra.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - * Roccat Pyra driver for Linux - * - * Copyright (c) 2010 Stefan Achatz - */ - -/* - * 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. - */ - -/* - * Roccat Pyra is a mobile gamer mouse which comes in wired and wireless - * variant. Wireless variant is not tested. - * Userland tools can be found at http://sourceforge.net/projects/roccat - */ - -#include -#include -#include -#include -#include -#include -#include "hid-ids.h" -#include "hid-roccat.h" -#include "hid-roccat-pyra.h" - -static void profile_activated(struct pyra_device *pyra, - unsigned int new_profile) -{ - pyra->actual_profile = new_profile; - pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi; -} - -static int pyra_send_control(struct usb_device *usb_dev, int value, - enum pyra_control_requests request) -{ - int len; - struct pyra_control control; - - if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || - request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) && - (value < 0 || value > 4)) - return -EINVAL; - - control.command = PYRA_COMMAND_CONTROL; - control.value = value; - control.request = request; - - len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_CONFIGURATION, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - PYRA_USB_COMMAND_CONTROL, 0, (char *)&control, - sizeof(struct pyra_control), - USB_CTRL_SET_TIMEOUT); - - if (len != sizeof(struct pyra_control)) - return len; - - return 0; -} - -static int pyra_receive_control_status(struct usb_device *usb_dev) -{ - int len; - struct pyra_control control; - - do { - msleep(10); - - len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | - USB_DIR_IN, - PYRA_USB_COMMAND_CONTROL, 0, (char *)&control, - sizeof(struct pyra_control), - USB_CTRL_SET_TIMEOUT); - - /* requested too early, try again */ - } while (len == -EPROTO); - - if (len == sizeof(struct pyra_control) && - control.command == PYRA_COMMAND_CONTROL && - control.request == PYRA_CONTROL_REQUEST_STATUS && - control.value == 1) - return 0; - else { - dev_err(&usb_dev->dev, "receive control status: " - "unknown response 0x%x 0x%x\n", - control.request, control.value); - return -EINVAL; - } -} - -static int pyra_get_profile_settings(struct usb_device *usb_dev, - struct pyra_profile_settings *buf, int number) -{ - int retval; - - retval = pyra_send_control(usb_dev, number, - PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); - - if (retval) - return retval; - - retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf, - sizeof(struct pyra_profile_settings), - USB_CTRL_SET_TIMEOUT); - - if (retval != sizeof(struct pyra_profile_settings)) - return retval; - - return 0; -} - -static int pyra_get_profile_buttons(struct usb_device *usb_dev, - struct pyra_profile_buttons *buf, int number) -{ - int retval; - - retval = pyra_send_control(usb_dev, number, - PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); - - if (retval) - return retval; - - retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf, - sizeof(struct pyra_profile_buttons), - USB_CTRL_SET_TIMEOUT); - - if (retval != sizeof(struct pyra_profile_buttons)) - return retval; - - return 0; -} - -static int pyra_get_settings(struct usb_device *usb_dev, - struct pyra_settings *buf) -{ - int len; - len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - PYRA_USB_COMMAND_SETTINGS, 0, buf, - sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT); - if (len != sizeof(struct pyra_settings)) - return -EIO; - return 0; -} - -static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) -{ - int len; - len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - PYRA_USB_COMMAND_INFO, 0, buf, - sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT); - if (len != sizeof(struct pyra_info)) - return -EIO; - return 0; -} - -static int pyra_set_profile_settings(struct usb_device *usb_dev, - struct pyra_profile_settings const *settings) -{ - int len; - len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_CONFIGURATION, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings, - sizeof(struct pyra_profile_settings), - USB_CTRL_SET_TIMEOUT); - if (len != sizeof(struct pyra_profile_settings)) - return -EIO; - if (pyra_receive_control_status(usb_dev)) - return -EIO; - return 0; -} - -static int pyra_set_profile_buttons(struct usb_device *usb_dev, - struct pyra_profile_buttons const *buttons) -{ - int len; - len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_CONFIGURATION, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons, - sizeof(struct pyra_profile_buttons), - USB_CTRL_SET_TIMEOUT); - if (len != sizeof(struct pyra_profile_buttons)) - return -EIO; - if (pyra_receive_control_status(usb_dev)) - return -EIO; - return 0; -} - -static int pyra_set_settings(struct usb_device *usb_dev, - struct pyra_settings const *settings) -{ - int len; - len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_CONFIGURATION, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings, - sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT); - if (len != sizeof(struct pyra_settings)) - return -EIO; - if (pyra_receive_control_status(usb_dev)) - return -EIO; - return 0; -} - -static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - - if (off >= sizeof(struct pyra_profile_settings)) - return 0; - - if (off + count > sizeof(struct pyra_profile_settings)) - count = sizeof(struct pyra_profile_settings) - off; - - mutex_lock(&pyra->pyra_lock); - memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off, - count); - mutex_unlock(&pyra->pyra_lock); - - return count; -} - -static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 0); -} - -static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 1); -} - -static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 2); -} - -static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 3); -} - -static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 4); -} - -static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - - if (off >= sizeof(struct pyra_profile_buttons)) - return 0; - - if (off + count > sizeof(struct pyra_profile_buttons)) - count = sizeof(struct pyra_profile_buttons) - off; - - mutex_lock(&pyra->pyra_lock); - memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off, - count); - mutex_unlock(&pyra->pyra_lock); - - return count; -} - -static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 0); -} - -static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 1); -} - -static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 2); -} - -static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 3); -} - -static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 4); -} - -static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); - int retval = 0; - int difference; - int profile_number; - struct pyra_profile_settings *profile_settings; - - if (off != 0 || count != sizeof(struct pyra_profile_settings)) - return -EINVAL; - - profile_number = ((struct pyra_profile_settings const *)buf)->number; - profile_settings = &pyra->profile_settings[profile_number]; - - mutex_lock(&pyra->pyra_lock); - difference = memcmp(buf, profile_settings, - sizeof(struct pyra_profile_settings)); - if (difference) { - retval = pyra_set_profile_settings(usb_dev, - (struct pyra_profile_settings const *)buf); - if (!retval) - memcpy(profile_settings, buf, - sizeof(struct pyra_profile_settings)); - } - mutex_unlock(&pyra->pyra_lock); - - if (retval) - return retval; - - return sizeof(struct pyra_profile_settings); -} - -static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); - int retval = 0; - int difference; - int profile_number; - struct pyra_profile_buttons *profile_buttons; - - if (off != 0 || count != sizeof(struct pyra_profile_buttons)) - return -EINVAL; - - profile_number = ((struct pyra_profile_buttons const *)buf)->number; - profile_buttons = &pyra->profile_buttons[profile_number]; - - mutex_lock(&pyra->pyra_lock); - difference = memcmp(buf, profile_buttons, - sizeof(struct pyra_profile_buttons)); - if (difference) { - retval = pyra_set_profile_buttons(usb_dev, - (struct pyra_profile_buttons const *)buf); - if (!retval) - memcpy(profile_buttons, buf, - sizeof(struct pyra_profile_buttons)); - } - mutex_unlock(&pyra->pyra_lock); - - if (retval) - return retval; - - return sizeof(struct pyra_profile_buttons); -} - -static ssize_t pyra_sysfs_read_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - - if (off >= sizeof(struct pyra_settings)) - return 0; - - if (off + count > sizeof(struct pyra_settings)) - count = sizeof(struct pyra_settings) - off; - - mutex_lock(&pyra->pyra_lock); - memcpy(buf, ((char const *)&pyra->settings) + off, count); - mutex_unlock(&pyra->pyra_lock); - - return count; -} - -static ssize_t pyra_sysfs_write_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); - int retval = 0; - int difference; - - if (off != 0 || count != sizeof(struct pyra_settings)) - return -EINVAL; - - mutex_lock(&pyra->pyra_lock); - difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings)); - if (difference) { - retval = pyra_set_settings(usb_dev, - (struct pyra_settings const *)buf); - if (!retval) - memcpy(&pyra->settings, buf, - sizeof(struct pyra_settings)); - } - mutex_unlock(&pyra->pyra_lock); - - if (retval) - return retval; - - profile_activated(pyra, pyra->settings.startup_profile); - - return sizeof(struct pyra_settings); -} - - -static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi); -} - -static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile); -} - -static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version); -} - -static ssize_t pyra_sysfs_show_startup_profile(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); - return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile); -} - -static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL); - -static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL); - -static DEVICE_ATTR(firmware_version, 0440, - pyra_sysfs_show_firmware_version, NULL); - -static DEVICE_ATTR(startup_profile, 0440, - pyra_sysfs_show_startup_profile, NULL); - -static struct attribute *pyra_attributes[] = { - &dev_attr_actual_cpi.attr, - &dev_attr_actual_profile.attr, - &dev_attr_firmware_version.attr, - &dev_attr_startup_profile.attr, - NULL -}; - -static struct attribute_group pyra_attribute_group = { - .attrs = pyra_attributes -}; - -static struct bin_attribute pyra_profile_settings_attr = { - .attr = { .name = "profile_settings", .mode = 0220 }, - .size = sizeof(struct pyra_profile_settings), - .write = pyra_sysfs_write_profile_settings -}; - -static struct bin_attribute pyra_profile1_settings_attr = { - .attr = { .name = "profile1_settings", .mode = 0440 }, - .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile1_settings -}; - -static struct bin_attribute pyra_profile2_settings_attr = { - .attr = { .name = "profile2_settings", .mode = 0440 }, - .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile2_settings -}; - -static struct bin_attribute pyra_profile3_settings_attr = { - .attr = { .name = "profile3_settings", .mode = 0440 }, - .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile3_settings -}; - -static struct bin_attribute pyra_profile4_settings_attr = { - .attr = { .name = "profile4_settings", .mode = 0440 }, - .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile4_settings -}; - -static struct bin_attribute pyra_profile5_settings_attr = { - .attr = { .name = "profile5_settings", .mode = 0440 }, - .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile5_settings -}; - -static struct bin_attribute pyra_profile_buttons_attr = { - .attr = { .name = "profile_buttons", .mode = 0220 }, - .size = sizeof(struct pyra_profile_buttons), - .write = pyra_sysfs_write_profile_buttons -}; - -static struct bin_attribute pyra_profile1_buttons_attr = { - .attr = { .name = "profile1_buttons", .mode = 0440 }, - .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile1_buttons -}; - -static struct bin_attribute pyra_profile2_buttons_attr = { - .attr = { .name = "profile2_buttons", .mode = 0440 }, - .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile2_buttons -}; - -static struct bin_attribute pyra_profile3_buttons_attr = { - .attr = { .name = "profile3_buttons", .mode = 0440 }, - .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile3_buttons -}; - -static struct bin_attribute pyra_profile4_buttons_attr = { - .attr = { .name = "profile4_buttons", .mode = 0440 }, - .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile4_buttons -}; - -static struct bin_attribute pyra_profile5_buttons_attr = { - .attr = { .name = "profile5_buttons", .mode = 0440 }, - .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile5_buttons -}; - -static struct bin_attribute pyra_settings_attr = { - .attr = { .name = "settings", .mode = 0660 }, - .size = sizeof(struct pyra_settings), - .read = pyra_sysfs_read_settings, - .write = pyra_sysfs_write_settings -}; - -static int pyra_create_sysfs_attributes(struct usb_interface *intf) -{ - int retval; - - retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group); - if (retval) - goto exit_1; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile_settings_attr); - if (retval) - goto exit_2; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile1_settings_attr); - if (retval) - goto exit_3; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile2_settings_attr); - if (retval) - goto exit_4; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile3_settings_attr); - if (retval) - goto exit_5; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile4_settings_attr); - if (retval) - goto exit_6; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile5_settings_attr); - if (retval) - goto exit_7; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile_buttons_attr); - if (retval) - goto exit_8; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile1_buttons_attr); - if (retval) - goto exit_9; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile2_buttons_attr); - if (retval) - goto exit_10; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile3_buttons_attr); - if (retval) - goto exit_11; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile4_buttons_attr); - if (retval) - goto exit_12; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile5_buttons_attr); - if (retval) - goto exit_13; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_settings_attr); - if (retval) - goto exit_14; - - return 0; - -exit_14: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); -exit_13: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); -exit_12: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); -exit_11: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); -exit_10: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); -exit_9: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); -exit_8: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); -exit_7: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); -exit_6: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); -exit_5: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); -exit_4: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); -exit_3: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); -exit_2: - sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); -exit_1: - return retval; -} - -static void pyra_remove_sysfs_attributes(struct usb_interface *intf) -{ - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); - sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); -} - -static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, - struct pyra_device *pyra) -{ - struct pyra_info *info; - int retval, i; - - mutex_init(&pyra->pyra_lock); - - info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - retval = pyra_get_info(usb_dev, info); - if (retval) { - kfree(info); - return retval; - } - pyra->firmware_version = info->firmware_version; - kfree(info); - - retval = pyra_get_settings(usb_dev, &pyra->settings); - if (retval) - return retval; - - for (i = 0; i < 5; ++i) { - retval = pyra_get_profile_settings(usb_dev, - &pyra->profile_settings[i], i); - if (retval) - return retval; - - retval = pyra_get_profile_buttons(usb_dev, - &pyra->profile_buttons[i], i); - if (retval) - return retval; - } - - profile_activated(pyra, pyra->settings.startup_profile); - - return 0; -} - -static int pyra_init_specials(struct hid_device *hdev) -{ - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct pyra_device *pyra; - int retval; - - if (intf->cur_altsetting->desc.bInterfaceProtocol - == USB_INTERFACE_PROTOCOL_MOUSE) { - - pyra = kzalloc(sizeof(*pyra), GFP_KERNEL); - if (!pyra) { - dev_err(&hdev->dev, "can't alloc device descriptor\n"); - return -ENOMEM; - } - hid_set_drvdata(hdev, pyra); - - retval = pyra_init_pyra_device_struct(usb_dev, pyra); - if (retval) { - dev_err(&hdev->dev, - "couldn't init struct pyra_device\n"); - goto exit_free; - } - - retval = roccat_connect(hdev); - if (retval < 0) { - dev_err(&hdev->dev, "couldn't init char dev\n"); - } else { - pyra->chrdev_minor = retval; - pyra->roccat_claimed = 1; - } - - retval = pyra_create_sysfs_attributes(intf); - if (retval) { - dev_err(&hdev->dev, "cannot create sysfs files\n"); - goto exit_free; - } - } else { - hid_set_drvdata(hdev, NULL); - } - - return 0; -exit_free: - kfree(pyra); - return retval; -} - -static void pyra_remove_specials(struct hid_device *hdev) -{ - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct pyra_device *pyra; - - if (intf->cur_altsetting->desc.bInterfaceProtocol - == USB_INTERFACE_PROTOCOL_MOUSE) { - pyra_remove_sysfs_attributes(intf); - pyra = hid_get_drvdata(hdev); - if (pyra->roccat_claimed) - roccat_disconnect(pyra->chrdev_minor); - kfree(hid_get_drvdata(hdev)); - } -} - -static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - int retval; - - retval = hid_parse(hdev); - if (retval) { - dev_err(&hdev->dev, "parse failed\n"); - goto exit; - } - - retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (retval) { - dev_err(&hdev->dev, "hw start failed\n"); - goto exit; - } - - retval = pyra_init_specials(hdev); - if (retval) { - dev_err(&hdev->dev, "couldn't install mouse\n"); - goto exit_stop; - } - return 0; - -exit_stop: - hid_hw_stop(hdev); -exit: - return retval; -} - -static void pyra_remove(struct hid_device *hdev) -{ - pyra_remove_specials(hdev); - hid_hw_stop(hdev); -} - -static void pyra_keep_values_up_to_date(struct pyra_device *pyra, - u8 const *data) -{ - struct pyra_mouse_event_button const *button_event; - - switch (data[0]) { - case PYRA_MOUSE_REPORT_NUMBER_BUTTON: - button_event = (struct pyra_mouse_event_button const *)data; - switch (button_event->type) { - case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: - profile_activated(pyra, button_event->data1 - 1); - break; - case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: - pyra->actual_cpi = button_event->data1; - break; - } - break; - } -} - -static void pyra_report_to_chrdev(struct pyra_device const *pyra, - u8 const *data) -{ - struct pyra_roccat_report roccat_report; - struct pyra_mouse_event_button const *button_event; - - if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON) - return; - - button_event = (struct pyra_mouse_event_button const *)data; - - switch (button_event->type) { - case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: - case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: - roccat_report.type = button_event->type; - roccat_report.value = button_event->data1; - roccat_report.key = 0; - roccat_report_event(pyra->chrdev_minor, - (uint8_t const *)&roccat_report, - sizeof(struct pyra_roccat_report)); - break; - case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO: - case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT: - case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH: - if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) { - roccat_report.type = button_event->type; - roccat_report.key = button_event->data1; - /* - * pyra reports profile numbers with range 1-5. - * Keeping this behaviour. - */ - roccat_report.value = pyra->actual_profile + 1; - roccat_report_event(pyra->chrdev_minor, - (uint8_t const *)&roccat_report, - sizeof(struct pyra_roccat_report)); - } - break; - } -} - -static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, - u8 *data, int size) -{ - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct pyra_device *pyra = hid_get_drvdata(hdev); - - if (intf->cur_altsetting->desc.bInterfaceProtocol - != USB_INTERFACE_PROTOCOL_MOUSE) - return 0; - - pyra_keep_values_up_to_date(pyra, data); - - if (pyra->roccat_claimed) - pyra_report_to_chrdev(pyra, data); - - return 0; -} - -static const struct hid_device_id pyra_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, - USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, - /* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */ - { } -}; - -MODULE_DEVICE_TABLE(hid, pyra_devices); - -static struct hid_driver pyra_driver = { - .name = "pyra", - .id_table = pyra_devices, - .probe = pyra_probe, - .remove = pyra_remove, - .raw_event = pyra_raw_event -}; - -static int __init pyra_init(void) -{ - return hid_register_driver(&pyra_driver); -} - -static void __exit pyra_exit(void) -{ - hid_unregister_driver(&pyra_driver); -} - -module_init(pyra_init); -module_exit(pyra_exit); - -MODULE_AUTHOR("Stefan Achatz"); -MODULE_DESCRIPTION("USB Roccat Pyra driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/hid/hid-roccat-pyra.h b/trunk/drivers/hid/hid-roccat-pyra.h deleted file mode 100644 index 22f80a8f26f9..000000000000 --- a/trunk/drivers/hid/hid-roccat-pyra.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef __HID_ROCCAT_PYRA_H -#define __HID_ROCCAT_PYRA_H - -/* - * Copyright (c) 2010 Stefan Achatz - */ - -/* - * 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. - */ - -#include - -#pragma pack(push) -#pragma pack(1) - -struct pyra_b { - uint8_t command; /* PYRA_COMMAND_B */ - uint8_t size; /* always 3 */ - uint8_t unknown; /* 1 */ -}; - -struct pyra_control { - uint8_t command; /* PYRA_COMMAND_CONTROL */ - /* - * value is profile number for request_settings and request_buttons - * 1 if status ok for request_status - */ - uint8_t value; /* Range 0-4 */ - uint8_t request; -}; - -enum pyra_control_requests { - PYRA_CONTROL_REQUEST_STATUS = 0x00, - PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, - PYRA_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20 -}; - -struct pyra_settings { - uint8_t command; /* PYRA_COMMAND_SETTINGS */ - uint8_t size; /* always 3 */ - uint8_t startup_profile; /* Range 0-4! */ -}; - -struct pyra_profile_settings { - uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */ - uint8_t size; /* always 0xd */ - uint8_t number; /* Range 0-4 */ - uint8_t xysync; - uint8_t x_sensitivity; /* 0x1-0xa */ - uint8_t y_sensitivity; - uint8_t x_cpi; /* unused */ - uint8_t y_cpi; /* this value is for x and y */ - uint8_t lightswitch; /* 0 = off, 1 = on */ - uint8_t light_effect; - uint8_t handedness; - uint16_t checksum; /* byte sum */ -}; - -struct pyra_profile_buttons { - uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */ - uint8_t size; /* always 0x13 */ - uint8_t number; /* Range 0-4 */ - uint8_t buttons[14]; - uint16_t checksum; /* byte sum */ -}; - -struct pyra_info { - uint8_t command; /* PYRA_COMMAND_INFO */ - uint8_t size; /* always 6 */ - uint8_t firmware_version; - uint8_t unknown1; /* always 0 */ - uint8_t unknown2; /* always 1 */ - uint8_t unknown3; /* always 0 */ -}; - -enum pyra_commands { - PYRA_COMMAND_CONTROL = 0x4, - PYRA_COMMAND_SETTINGS = 0x5, - PYRA_COMMAND_PROFILE_SETTINGS = 0x6, - PYRA_COMMAND_PROFILE_BUTTONS = 0x7, - PYRA_COMMAND_INFO = 0x9, - PYRA_COMMAND_B = 0xb -}; - -enum pyra_usb_commands { - PYRA_USB_COMMAND_CONTROL = 0x304, - PYRA_USB_COMMAND_SETTINGS = 0x305, - PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306, - PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307, - PYRA_USB_COMMAND_INFO = 0x309, - PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */ -}; - -enum pyra_mouse_report_numbers { - PYRA_MOUSE_REPORT_NUMBER_HID = 1, - PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2, - PYRA_MOUSE_REPORT_NUMBER_BUTTON = 3, -}; - -struct pyra_mouse_event_button { - uint8_t report_number; /* always 3 */ - uint8_t unknown; /* always 0 */ - uint8_t type; - uint8_t data1; - uint8_t data2; -}; - -struct pyra_mouse_event_audio { - uint8_t report_number; /* always 2 */ - uint8_t type; - uint8_t unused; /* always 0 */ -}; - -/* hid audio controls */ -enum pyra_mouse_event_audio_types { - PYRA_MOUSE_EVENT_AUDIO_TYPE_MUTE = 0xe2, - PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_UP = 0xe9, - PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_DOWN = 0xea, -}; - -enum pyra_mouse_event_button_types { - /* - * Mouse sends tilt events on report_number 1 and 3 - * Tilt events are sent repeatedly with 0.94s between first and second - * event and 0.22s on subsequent - */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_TILT = 0x10, - - /* - * These are sent sequentially - * data1 contains new profile number in range 1-5 - */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_1 = 0x20, - PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2 = 0x30, - - /* - * data1 = button_number (rmp index) - * data2 = pressed/released - */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO = 0x40, - PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT = 0x50, - - /* - * data1 = button_number (rmp index) - */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH = 0x60, - - /* data1 = new cpi */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI = 0xb0, - - /* data1 and data2 = new sensitivity */ - PYRA_MOUSE_EVENT_BUTTON_TYPE_SENSITIVITY = 0xc0, - - PYRA_MOUSE_EVENT_BUTTON_TYPE_MULTIMEDIA = 0xf0, -}; - -enum { - PYRA_MOUSE_EVENT_BUTTON_PRESS = 0, - PYRA_MOUSE_EVENT_BUTTON_RELEASE = 1, -}; - -struct pyra_roccat_report { - uint8_t type; - uint8_t value; - uint8_t key; -}; - -#pragma pack(pop) - -struct pyra_device { - int actual_profile; - int actual_cpi; - int firmware_version; - int roccat_claimed; - int chrdev_minor; - struct mutex pyra_lock; - struct pyra_settings settings; - struct pyra_profile_settings profile_settings[5]; - struct pyra_profile_buttons profile_buttons[5]; -}; - -#endif diff --git a/trunk/drivers/hid/hid-samsung.c b/trunk/drivers/hid/hid-samsung.c index 35894444e000..bda0fd60c98d 100644 --- a/trunk/drivers/hid/hid-samsung.c +++ b/trunk/drivers/hid/hid-samsung.c @@ -61,10 +61,10 @@ static inline void samsung_irda_dev_trace(struct hid_device *hdev, "descriptor\n", rsize); } -static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && + if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && rdesc[177] == 0x75 && rdesc[178] == 0x30 && rdesc[179] == 0x95 && rdesc[180] == 0x01 && rdesc[182] == 0x40) { @@ -74,25 +74,24 @@ static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[180] = 0x06; rdesc[182] = 0x42; } else - if (*rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && + if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && rdesc[194] == 0x25 && rdesc[195] == 0x12) { samsung_irda_dev_trace(hdev, 203); rdesc[193] = 0x1; rdesc[195] = 0xf; } else - if (*rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && + if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && rdesc[126] == 0x25 && rdesc[127] == 0x11) { samsung_irda_dev_trace(hdev, 135); rdesc[125] = 0x1; rdesc[127] = 0xe; } else - if (*rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 && + if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 && rdesc[162] == 0x25 && rdesc[163] == 0x01) { samsung_irda_dev_trace(hdev, 171); rdesc[161] = 0x1; rdesc[163] = 0x3; } - return rdesc; } #define samsung_kbd_mouse_map_key_clear(c) \ @@ -131,12 +130,11 @@ static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev, return 1; } -static __u8 *samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) - rdesc = samsung_irda_report_fixup(hdev, rdesc, rsize); - return rdesc; + samsung_irda_report_fixup(hdev, rdesc, rsize); } static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi, diff --git a/trunk/drivers/hid/hid-sony.c b/trunk/drivers/hid/hid-sony.c index 677bb3da10e8..402d5574b574 100644 --- a/trunk/drivers/hid/hid-sony.c +++ b/trunk/drivers/hid/hid-sony.c @@ -24,46 +24,24 @@ #include "hid-ids.h" -#define VAIO_RDESC_CONSTANT (1 << 0) -#define SIXAXIS_CONTROLLER_USB (1 << 1) -#define SIXAXIS_CONTROLLER_BT (1 << 2) +#define VAIO_RDESC_CONSTANT 0x0001 struct sony_sc { unsigned long quirks; }; /* Sony Vaio VGX has wrongly mouse pointer declared as constant */ -static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { struct sony_sc *sc = hid_get_drvdata(hdev); if ((sc->quirks & VAIO_RDESC_CONSTANT) && - *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { + rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " "descriptor\n"); rdesc[55] = 0x06; } - return rdesc; -} - -static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, - size_t count, unsigned char report_type) -{ - struct usb_interface *intf = to_usb_interface(hid->dev.parent); - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *interface = intf->cur_altsetting; - int report_id = buf[0]; - int ret; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - HID_REQ_SET_REPORT, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ((report_type + 1) << 8) | report_id, - interface->desc.bInterfaceNumber, buf, count, - USB_CTRL_SET_TIMEOUT); - - return ret; } /* @@ -71,7 +49,7 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, * to "operational". Without this, the ps3 controller will not report any * events. */ -static int sixaxis_set_operational_usb(struct hid_device *hdev) +static int sony_set_operational_usb(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(intf); @@ -96,7 +74,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) return ret; } -static int sixaxis_set_operational_bt(struct hid_device *hdev) +static int sony_set_operational_bt(struct hid_device *hdev) { unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); @@ -130,14 +108,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - if (sc->quirks & SIXAXIS_CONTROLLER_USB) { - hdev->hid_output_raw_report = sixaxis_usb_output_raw_report; - ret = sixaxis_set_operational_usb(hdev); - } - else if (sc->quirks & SIXAXIS_CONTROLLER_BT) - ret = sixaxis_set_operational_bt(hdev); - else + switch (hdev->bus) { + case BUS_USB: + ret = sony_set_operational_usb(hdev); + break; + case BUS_BLUETOOTH: + ret = sony_set_operational_bt(hdev); + break; + default: ret = 0; + } if (ret < 0) goto err_stop; @@ -157,10 +137,8 @@ static void sony_remove(struct hid_device *hdev) } static const struct hid_device_id sony_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), - .driver_data = SIXAXIS_CONTROLLER_USB }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), - .driver_data = SIXAXIS_CONTROLLER_BT }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, { } diff --git a/trunk/drivers/hid/hid-stantum.c b/trunk/drivers/hid/hid-stantum.c index 3171be28c3d5..90df886c5e04 100644 --- a/trunk/drivers/hid/hid-stantum.c +++ b/trunk/drivers/hid/hid-stantum.c @@ -249,8 +249,6 @@ static void stantum_remove(struct hid_device *hdev) static const struct hid_device_id stantum_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) }, { } }; MODULE_DEVICE_TABLE(hid, stantum_devices); diff --git a/trunk/drivers/hid/hid-sunplus.c b/trunk/drivers/hid/hid-sunplus.c index 164ed568f6cf..438107d9f1b2 100644 --- a/trunk/drivers/hid/hid-sunplus.c +++ b/trunk/drivers/hid/hid-sunplus.c @@ -22,17 +22,16 @@ #include "hid-ids.h" -static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && + if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && rdesc[106] == 0x03) { dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop " "report descriptor\n"); rdesc[105] = rdesc[110] = 0x03; rdesc[106] = rdesc[111] = 0x21; } - return rdesc; } #define sp_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ diff --git a/trunk/drivers/hid/hid-uclogic.c b/trunk/drivers/hid/hid-uclogic.c deleted file mode 100644 index 05fdc85a76e5..000000000000 --- a/trunk/drivers/hid/hid-uclogic.c +++ /dev/null @@ -1,623 +0,0 @@ -/* - * HID driver for UC-Logic devices not fully compliant with HID standard - * - * Copyright (c) 2010 Nikolai Kondrashov - */ - -/* - * 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. - */ - -#include -#include -#include - -#include "hid-ids.h" - -/* - * The original descriptors of WPXXXXU tablets have three report IDs, of - * which only two are used (8 and 9), and the remaining (7) seems to have - * the originally intended pen description which was abandoned for some - * reason. From this unused description it is possible to extract the - * actual physical extents and resolution. All the models use the same - * descriptor with different extents for the unused report ID. - * - * Here it is: - * - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Pen), ; Pen (02h, application collection) - * Collection (Application), - * Report ID (7), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (Tip Switch), ; Tip switch (42h, momentary control) - * Usage (Barrel Switch), ; Barrel switch (44h, momentary control) - * Usage (Eraser), ; Eraser (45h, momentary control) - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (3), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage (In Range), ; In range (32h, momentary control) - * Report Count (1), - * Input (Variable), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Physical Minimum (0), - * Physical Maximum (Xpm), - * Logical Maximum (Xlm), - * Input (Variable), - * Usage (Y), ; Y (31h, dynamic value) - * Physical Maximum (Ypm), - * Logical Maximum (Ylm), - * Input (Variable), - * Pop, - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Maximum (1023), - * Input (Variable), - * Report Size (16), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (8), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (03h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Count (3), - * Report Size (1), - * Input (Variable), - * Report Count (5), - * Input (Constant), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Usage (Wheel), ; Wheel (38h, dynamic value) - * Usage (00h), - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (4), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (9), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (03h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Count (3), - * Report Size (1), - * Input (Variable), - * Report Count (5), - * Input (Constant), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (32767), - * Physical Minimum (0), - * Physical Maximum (32767), - * Report Count (2), - * Report Size (16), - * Input (Variable), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Maximum (1023), - * Report Count (1), - * Report Size (16), - * Input (Variable), - * End Collection, - * End Collection - * - * Here are the extents values for the WPXXXXU models: - * - * Xpm Xlm Ypm Ylm - * WP4030U 4000 8000 3000 6000 - * WP5540U 5500 11000 4000 8000 - * WP8060U 8000 16000 6000 12000 - * - * This suggests that all of them have 2000 LPI resolution, as advertised. - */ - -/* Size of the original descriptor of WPXXXXU tablets */ -#define WPXXXXU_RDESC_ORIG_SIZE 212 - -/* - * Fixed WP4030U report descriptor. - * Although the hardware might actually support it, the mouse description - * has been removed, since there seems to be no devices having one and it - * wouldn't make much sense because of the working area size. - */ -static __u8 wp4030u_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x09, /* Report ID (9), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* Fixed WP5540U report descriptor */ -static __u8 wp5540u_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x09, /* Report ID (9), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x02, /* Usage (Mouse), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x03, /* Usage Maximum (03h), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x75, 0x08, /* Report Size (8), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x15, 0x81, /* Logical Minimum (-127), */ - 0x25, 0x7F, /* Logical Maximum (127), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x09, 0x38, /* Usage (Wheel), */ - 0x15, 0xFF, /* Logical Minimum (-1), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x81, 0x01, /* Input (Constant), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* Fixed WP8060U report descriptor */ -static __u8 wp8060u_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x09, /* Report ID (9), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0x70, 0x17, /* Physical Maximum (6000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x02, /* Usage (Mouse), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x03, /* Usage Maximum (03h), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x75, 0x08, /* Report Size (8), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x15, 0x81, /* Logical Minimum (-127), */ - 0x25, 0x7F, /* Logical Maximum (127), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x09, 0x38, /* Usage (Wheel), */ - 0x15, 0xFF, /* Logical Minimum (-1), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x81, 0x01, /* Input (Constant), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* - * Original PF1209 report descriptor. - * - * The descriptor is similar to WPXXXXU descriptors, with an addition of a - * feature report (ID 4) of unknown purpose. - * - * Although the advertised resolution is 4000 LPI the unused report ID - * (taken from WPXXXXU, it seems) states 2000 LPI, but it is probably - * incorrect and is a result of blind copying without understanding. Anyway - * the real logical extents are always scaled to 0..32767, which IMHO spoils - * the precision. - * - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Pen), ; Pen (02h, application collection) - * Collection (Application), - * Report ID (7), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (Tip Switch), ; Tip switch (42h, momentary control) - * Usage (Barrel Switch), ; Barrel switch (44h, momentary control) - * Usage (Eraser), ; Eraser (45h, momentary control) - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (3), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage (In Range), ; In range (32h, momentary control) - * Report Count (1), - * Input (Variable), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Physical Minimum (0), - * Physical Maximum (12000), - * Logical Maximum (24000), - * Input (Variable), - * Usage (Y), ; Y (31h, dynamic value) - * Physical Maximum (9000), - * Logical Maximum (18000), - * Input (Variable), - * Pop, - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Maximum (1023), - * Input (Variable), - * Report Size (16), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (8), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (03h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Count (3), - * Report Size (1), - * Input (Variable), - * Report Count (5), - * Input (Constant), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Usage (Wheel), ; Wheel (38h, dynamic value) - * Usage (00h), - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (4), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (9), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (03h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Count (3), - * Report Size (1), - * Input (Variable), - * Report Count (5), - * Input (Constant), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (32767), - * Physical Minimum (0), - * Physical Maximum (32767), - * Report Count (2), - * Report Size (16), - * Input (Variable), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Maximum (1023), - * Report Count (1), - * Report Size (16), - * Input (Variable), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (00h), - * Collection (Application), - * Report ID (4), - * Logical Minimum (0), - * Logical Maximum (255), - * Usage (00h), - * Report Size (8), - * Report Count (3), - * Feature (Variable), - * End Collection - */ - -/* Size of the original descriptor of PF1209 tablet */ -#define PF1209_RDESC_ORIG_SIZE 234 - -/* - * Fixed PF1209 report descriptor - * - * The descriptor is fixed similarly to WP5540U and WP8060U, plus the - * feature report is removed, because its purpose is unknown and it is of no - * use to the generic HID driver anyway for now. - */ -static __u8 pf1209_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x09, /* Report ID (9), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0x28, 0x23, /* Physical Maximum (9000), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x02, /* Usage (Mouse), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x01, /* Report Size (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x03, /* Usage Maximum (03h), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x05, /* Report Count (5), */ - 0x81, 0x01, /* Input (Constant), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x75, 0x08, /* Report Size (8), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x15, 0x81, /* Logical Minimum (-127), */ - 0x25, 0x7F, /* Logical Maximum (127), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x09, 0x38, /* Usage (Wheel), */ - 0x15, 0xFF, /* Logical Minimum (-1), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x81, 0x01, /* Input (Constant), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - switch (hdev->product) { - case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209: - if (*rsize == PF1209_RDESC_ORIG_SIZE) { - rdesc = pf1209_rdesc_fixed; - *rsize = sizeof(pf1209_rdesc_fixed); - } - break; - case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U: - if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) { - rdesc = wp4030u_rdesc_fixed; - *rsize = sizeof(wp4030u_rdesc_fixed); - } - break; - case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U: - if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) { - rdesc = wp5540u_rdesc_fixed; - *rsize = sizeof(wp5540u_rdesc_fixed); - } - break; - case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U: - if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) { - rdesc = wp8060u_rdesc_fixed; - *rsize = sizeof(wp8060u_rdesc_fixed); - } - break; - } - - return rdesc; -} - -static const struct hid_device_id uclogic_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, - USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, - USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, - USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, - USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, - { } -}; -MODULE_DEVICE_TABLE(hid, uclogic_devices); - -static struct hid_driver uclogic_driver = { - .name = "uclogic", - .id_table = uclogic_devices, - .report_fixup = uclogic_report_fixup, -}; - -static int __init uclogic_init(void) -{ - return hid_register_driver(&uclogic_driver); -} - -static void __exit uclogic_exit(void) -{ - hid_unregister_driver(&uclogic_driver); -} - -module_init(uclogic_init); -module_exit(uclogic_exit); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/hid/hid-waltop.c b/trunk/drivers/hid/hid-waltop.c deleted file mode 100644 index b3a4163f2e67..000000000000 --- a/trunk/drivers/hid/hid-waltop.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * HID driver for Waltop devices not fully compliant with HID standard - * - * Copyright (c) 2010 Nikolai Kondrashov - */ - -/* - * 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. - */ - -#include -#include -#include - -#include "hid-ids.h" - -/* - * There exists an official driver on the manufacturer's website, which - * wasn't submitted to the kernel, for some reason. The official driver - * doesn't seem to support extra features of some tablets, like wheels. - * - * It shows that the feature report ID 2 could be used to control any waltop - * tablet input mode, switching it between "default", "tablet" and "ink". - * - * This driver only uses "default" mode for all the supported tablets. This - * mode tries to be HID-compatible (not very successfully), but cripples the - * resolution of some tablets. - * - * The "tablet" mode uses some proprietary, yet decipherable protocol, which - * represents the correct resolution, but is possibly HID-incompatible (i.e. - * indescribable by a report descriptor). - * - * The purpose of the "ink" mode is unknown. - * - * The feature reports needed for switching to each mode are these: - * - * 02 16 00 default - * 02 16 01 tablet - * 02 16 02 ink - */ - -/* - * Original Slim Tablet 5.8 inch report descriptor. - * - * All the reports except the report with ID 16 (the stylus) are unused, - * possibly because the tablet is not configured to, or because they were - * just copied from a more capable model. The full purpose of features - * described for report ID 2 is unknown. - * - * The stylus buttons are described as three bit fields, whereas actually - * it's an "array", i.e. they're reported as button numbers (1, 2 and 3). - * The "eraser" field is not used. There is also a "push" without a "pop" in - * the stylus description. - * - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (1), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (05h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Size (3), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Usage (Wheel), ; Wheel (38h, dynamic value) - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (3), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Pen), ; Pen (02h, application collection) - * Collection (Application), - * Report ID (2), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * Usage (Azimuth), ; Azimuth (3Fh, dynamic value) - * Usage (Altitude), ; Altitude (40h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (2), - * Feature (Variable), - * End Collection, - * Report ID (5), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (10), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (3), - * Input (Variable), - * End Collection, - * Report ID (16), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (Tip Switch), ; Tip switch (42h, momentary control) - * Usage (Barrel Switch), ; Barrel switch (44h, momentary control) - * Usage (Invert), ; Invert (3Ch, momentary control) - * Usage (Eraser), ; Eraser (45h, momentary control) - * Usage (In Range), ; In range (32h, momentary control) - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Logical Minimum (0), - * Logical Maximum (10000), - * Physical Minimum (0), - * Physical Maximum (10000), - * Input (Variable), - * Usage (Y), ; Y (31h, dynamic value) - * Logical Maximum (6000), - * Physical Maximum (6000), - * Input (Variable), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (1023), - * Physical Minimum (0), - * Physical Maximum (1023), - * Input (Variable), - * End Collection, - * End Collection - */ - -/* Size of the original report descriptor of Slim Tablet 5.8 inch */ -#define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE 222 - -/* - * Fixed Slim Tablet 5.8 inch descriptor. - * - * All the reports except the stylus report (ID 16) were removed as unused. - * The stylus buttons description was fixed. - */ -static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x10, /* Report ID (16), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x15, 0x01, /* Logical Minimum (1), */ - 0x25, 0x03, /* Logical Maximum (3), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x80, /* Input, */ - 0x09, 0x32, /* Usage (In Range), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0x88, 0x13, /* Physical Maximum (5000), */ - 0x26, 0x10, 0x27, /* Logical Maximum (10000), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */ - 0x26, 0x70, 0x17, /* Logical Maximum (6000), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* - * Original Slim Tablet 12.1 inch report descriptor. - * - * The descriptor is similar to the Slim Tablet 5.8 inch descriptor with the - * addition of a keyboard report, seemingly unused. It may have get here - * from a Media Tablet - probably an unimplemented feature. - * - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Mouse), ; Mouse (02h, application collection) - * Collection (Application), - * Report ID (1), - * Usage (Pointer), ; Pointer (01h, physical collection) - * Collection (Physical), - * Usage Page (Button), ; Button (09h) - * Usage Minimum (01h), - * Usage Maximum (05h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Size (3), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Usage (Y), ; Y (31h, dynamic value) - * Usage (Wheel), ; Wheel (38h, dynamic value) - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (3), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Pen), ; Pen (02h, application collection) - * Collection (Application), - * Report ID (2), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * Usage (Azimuth), ; Azimuth (3Fh, dynamic value) - * Usage (Altitude), ; Altitude (40h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (2), - * Feature (Variable), - * End Collection, - * Report ID (5), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (10), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (3), - * Input (Variable), - * End Collection, - * Report ID (16), - * Usage (Stylus), ; Stylus (20h, logical collection) - * Collection (Physical), - * Usage (Tip Switch), ; Tip switch (42h, momentary control) - * Usage (Barrel Switch), ; Barrel switch (44h, momentary control) - * Usage (Invert), ; Invert (3Ch, momentary control) - * Usage (Eraser), ; Eraser (45h, momentary control) - * Usage (In Range), ; In range (32h, momentary control) - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (X), ; X (30h, dynamic value) - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Logical Minimum (0), - * Logical Maximum (20000), - * Physical Minimum (0), - * Physical Maximum (20000), - * Input (Variable), - * Usage (Y), ; Y (31h, dynamic value) - * Logical Maximum (12500), - * Physical Maximum (12500), - * Input (Variable), - * Usage Page (Digitizer), ; Digitizer (0Dh) - * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (1023), - * Physical Minimum (0), - * Physical Maximum (1023), - * Input (Variable), - * End Collection, - * End Collection, - * Usage Page (Desktop), ; Generic desktop controls (01h) - * Usage (Keyboard), ; Keyboard (06h, application collection) - * Collection (Application), - * Report ID (13), - * Usage Page (Keyboard), ; Keyboard/keypad (07h) - * Usage Minimum (KB Leftcontrol), ; Keyboard left control - * ; (E0h, dynamic value) - * Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value) - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (8), - * Input (Variable), - * Report Size (8), - * Report Count (1), - * Input (Constant), - * Usage Page (Keyboard), ; Keyboard/keypad (07h) - * Usage Minimum (None), ; No event (00h, selector) - * Usage Maximum (KB Application), ; Keyboard Application (65h, selector) - * Logical Minimum (0), - * Logical Maximum (101), - * Report Size (8), - * Report Count (5), - * Input, - * End Collection - */ - -/* Size of the original report descriptor of Slim Tablet 12.1 inch */ -#define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE 269 - -/* - * Fixed Slim Tablet 12.1 inch descriptor. - * - * All the reports except the stylus report (ID 16) were removed as unused. - * The stylus buttons description was fixed. - */ -static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x10, /* Report ID (16), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x15, 0x01, /* Logical Minimum (1), */ - 0x25, 0x03, /* Logical Maximum (3), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x80, /* Input, */ - 0x09, 0x32, /* Usage (In Range), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ - 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0x6A, 0x18, /* Physical Maximum (6250), */ - 0x26, 0xD4, 0x30, /* Logical Maximum (12500), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* - * Original Media Tablet 10.6 inch report descriptor. - * - * There are at least two versions of this model in the wild. They are - * represented by Genius G-Pen M609 (older version) and Genius G-Pen M609X - * (newer version). - * - * Both versions have the usual pen with two barrel buttons and two - * identical wheels with center buttons in the top corners of the tablet - * base. They also have buttons on the top, between the wheels, for - * selecting the wheels' functions and wide/standard mode. In the wide mode - * the whole working surface is sensed, in the standard mode a narrower area - * is sensed, but the logical report extents remain the same. These modes - * correspond roughly to 16:9 and 4:3 aspect ratios respectively. - * - * The older version has three wheel function buttons ("scroll", "zoom" and - * "volume") and two separate buttons for wide and standard mode. The newer - * version has four wheel function buttons (plus "brush") and only one - * button is used for selecting wide/standard mode. So, the total number of - * buttons remains the same, but one of the mode buttons is repurposed as a - * wheels' function button in the newer version. - * - * The wheel functions are: - * scroll - the wheels act as scroll wheels, the center buttons switch - * between vertical and horizontal scrolling; - * zoom - the wheels zoom in/out, the buttons supposedly reset to 100%; - * volume - the wheels control the sound volume, the buttons mute; - * brush - the wheels are supposed to control brush width in a graphics - * editor, the buttons do nothing. - * - * Below is the newer version's report descriptor. It may very well be that - * the older version's descriptor is different and thus it won't be - * supported. - * - * The mouse report (ID 1) only uses the wheel field for reporting the tablet - * wheels' scroll mode. The keyboard report (ID 13) is used to report the - * wheels' zoom and brush control functions as key presses. The report ID 12 - * is used to report the wheels' volume control functions. The stylus report - * (ID 16) has the same problems as the Slim Tablet 5.8 inch report has. - * - * The rest of the reports are unused, at least in the default configuration. - * The purpose of the features is unknown. - * - * Usage Page (Desktop), - * Usage (Mouse), - * Collection (Application), - * Report ID (1), - * Usage (Pointer), - * Collection (Physical), - * Usage Page (Button), - * Usage Minimum (01h), - * Usage Maximum (05h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Size (3), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), - * Usage (X), - * Usage (Y), - * Usage (Wheel), - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (3), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Digitizer), - * Usage (Pen), - * Collection (Application), - * Report ID (2), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * Usage (Azimuth), - * Usage (Altitude), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (2), - * Feature (Variable), - * End Collection, - * Report ID (5), - * Usage Page (Digitizer), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (10), - * Usage Page (Digitizer), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (16), - * Usage (Stylus), - * Collection (Physical), - * Usage (Tip Switch), - * Usage (Barrel Switch), - * Usage (Invert), - * Usage (Eraser), - * Usage (In Range), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage Page (Desktop), - * Usage (X), - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Logical Minimum (0), - * Logical Maximum (18000), - * Physical Minimum (0), - * Physical Maximum (18000), - * Input (Variable), - * Usage (Y), - * Logical Maximum (11000), - * Physical Maximum (11000), - * Input (Variable), - * Usage Page (Digitizer), - * Usage (Tip Pressure), - * Logical Minimum (0), - * Logical Maximum (1023), - * Physical Minimum (0), - * Physical Maximum (1023), - * Input (Variable), - * End Collection, - * End Collection, - * Usage Page (Desktop), - * Usage (Keyboard), - * Collection (Application), - * Report ID (13), - * Usage Page (Keyboard), - * Usage Minimum (KB Leftcontrol), - * Usage Maximum (KB Right GUI), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (8), - * Input (Variable), - * Report Size (8), - * Report Count (1), - * Input (Constant), - * Usage Page (Keyboard), - * Usage Minimum (None), - * Usage Maximum (KB Application), - * Logical Minimum (0), - * Logical Maximum (101), - * Report Size (8), - * Report Count (5), - * Input, - * End Collection, - * Usage Page (Consumer), - * Usage (Consumer Control), - * Collection (Application), - * Report ID (12), - * Usage (Volume Inc), - * Usage (Volume Dec), - * Usage (Mute), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (3), - * Input (Variable, Relative), - * Report Size (5), - * Report Count (1), - * Input (Constant, Variable, Relative), - * End Collection - */ - -/* Size of the original report descriptor of Media Tablet 10.6 inch */ -#define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE 300 - -/* - * Fixed Media Tablet 10.6 inch descriptor. - * - * The descriptions of reports unused in the default configuration are - * removed. The stylus report (ID 16) is fixed similarly to Slim Tablet 5.8 - * inch. The unused mouse report (ID 1) fields are replaced with constant - * padding. - * - * The keyboard report (ID 13) is hacked to instead have an "array" field - * reporting consumer page controls, and all the unused bits are masked out - * with constant padding. The "brush" wheels' function is represented as "Scan - * Previous/Next Track" controls due to the lack of brush controls in the - * usage tables specification. - */ -static __u8 media_tablet_10_6_inch_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x10, /* Report ID (16), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x15, 0x01, /* Logical Minimum (1), */ - 0x25, 0x03, /* Logical Maximum (3), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x80, /* Input, */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x32, /* Usage (In Range), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0x28, 0x23, /* Physical Maximum (9000), */ - 0x26, 0x50, 0x46, /* Logical Maximum (18000), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */ - 0x26, 0xF8, 0x2A, /* Logical Maximum (11000), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x02, /* Usage (Mouse), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x01, /* Report ID (1), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x95, 0x02, /* Report Count (2), */ - 0x15, 0xFF, /* Logical Minimum (-1), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x09, 0x38, /* Usage (Wheel), */ - 0x0B, 0x38, 0x02, /* Usage (Consumer AC Pan), */ - 0x0C, 0x00, - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x0C, /* Usage Page (Consumer), */ - 0x09, 0x01, /* Usage (Consumer Control), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x0D, /* Report ID (13), */ - 0x95, 0x01, /* Report Count (1), */ - 0x75, 0x10, /* Report Size (16), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */ - 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ - 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ - 0x09, 0xB6, /* Usage (Scan Previous Track), */ - 0x09, 0xB5, /* Usage (Scan Next Track), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ - 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ - 0x15, 0x0C, /* Logical Minimum (12), */ - 0x25, 0x17, /* Logical Maximum (23), */ - 0x75, 0x05, /* Report Size (5), */ - 0x80, /* Input, */ - 0x75, 0x03, /* Report Size (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x20, /* Report Size (32), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0xC0, /* End Collection, */ - 0x09, 0x01, /* Usage (Consumer Control), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x0C, /* Report ID (12), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0xE9, /* Usage (Volume Inc), */ - 0x09, 0xEA, /* Usage (Volume Dec), */ - 0x09, 0xE2, /* Usage (Mute), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x95, 0x35, /* Report Count (53), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0xC0 /* End Collection */ -}; - -/* - * Original Media Tablet 14.1 inch report descriptor. - * - * There are at least two versions of this model in the wild. They are - * represented by Genius G-Pen M712 (older version) and Genius G-Pen M712X - * (newer version). The hardware difference between these versions is the same - * as between older and newer versions of Media Tablet 10.6 inch. The report - * descriptors are identical for both versions. - * - * The function, behavior and report descriptor of this tablet is similar to - * that of Media Tablet 10.6 inch. However, there is one more field (with - * Consumer AC Pan usage) in the mouse description. Then the tablet X and Y - * logical extents both get scaled to 0..16383 range (a hardware limit?), - * which kind of defeats the advertised 4000 LPI resolution, considering the - * physical extents of 12x7.25 inches. Plus, reports 5, 10 and 255 are used - * sometimes (while moving the pen) with unknown purpose. Also, the key codes - * generated for zoom in/out are different. - * - * Usage Page (Desktop), - * Usage (Mouse), - * Collection (Application), - * Report ID (1), - * Usage (Pointer), - * Collection (Physical), - * Usage Page (Button), - * Usage Minimum (01h), - * Usage Maximum (05h), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Size (3), - * Report Count (1), - * Input (Constant, Variable), - * Usage Page (Desktop), - * Usage (X), - * Usage (Y), - * Usage (Wheel), - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (3), - * Input (Variable, Relative), - * Usage Page (Consumer), - * Logical Minimum (-127), - * Logical Maximum (127), - * Report Size (8), - * Report Count (1), - * Usage (AC Pan), - * Input (Variable, Relative), - * End Collection, - * End Collection, - * Usage Page (Digitizer), - * Usage (Pen), - * Collection (Application), - * Report ID (2), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * Usage (Azimuth), - * Usage (Altitude), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (2), - * Feature (Variable), - * End Collection, - * Report ID (5), - * Usage Page (Digitizer), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (10), - * Usage Page (Digitizer), - * Usage (Stylus), - * Collection (Physical), - * Usage (00h), - * Logical Minimum (0), - * Logical Maximum (255), - * Report Size (8), - * Report Count (7), - * Input (Variable), - * End Collection, - * Report ID (16), - * Usage (Stylus), - * Collection (Physical), - * Usage (Tip Switch), - * Usage (Barrel Switch), - * Usage (Invert), - * Usage (Eraser), - * Usage (In Range), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (5), - * Input (Variable), - * Report Count (3), - * Input (Constant, Variable), - * Usage Page (Desktop), - * Usage (X), - * Report Size (16), - * Report Count (1), - * Push, - * Unit Exponent (13), - * Unit (Inch^3), - * Logical Minimum (0), - * Logical Maximum (16383), - * Physical Minimum (0), - * Physical Maximum (16383), - * Input (Variable), - * Usage (Y), - * Input (Variable), - * Usage Page (Digitizer), - * Usage (Tip Pressure), - * Logical Minimum (0), - * Logical Maximum (1023), - * Physical Minimum (0), - * Physical Maximum (1023), - * Input (Variable), - * End Collection, - * End Collection, - * Usage Page (Desktop), - * Usage (Keyboard), - * Collection (Application), - * Report ID (13), - * Usage Page (Keyboard), - * Usage Minimum (KB Leftcontrol), - * Usage Maximum (KB Right GUI), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (8), - * Input (Variable), - * Report Size (8), - * Report Count (1), - * Input (Constant), - * Usage Page (Keyboard), - * Usage Minimum (None), - * Usage Maximum (KB Application), - * Logical Minimum (0), - * Logical Maximum (101), - * Report Size (8), - * Report Count (5), - * Input, - * End Collection, - * Usage Page (Consumer), - * Usage (Consumer Control), - * Collection (Application), - * Report ID (12), - * Usage (Volume Inc), - * Usage (Volume Dec), - * Usage (Mute), - * Logical Minimum (0), - * Logical Maximum (1), - * Report Size (1), - * Report Count (3), - * Input (Variable, Relative), - * Report Size (5), - * Report Count (1), - * Input (Constant, Variable, Relative), - * End Collection - */ - -/* Size of the original report descriptor of Media Tablet 14.1 inch */ -#define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE 309 - -/* - * Fixed Media Tablet 14.1 inch descriptor. - * It is fixed similarly to the Media Tablet 10.6 inch descriptor. - */ -static __u8 media_tablet_14_1_inch_rdesc_fixed[] = { - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x10, /* Report ID (16), */ - 0x09, 0x20, /* Usage (Stylus), */ - 0xA0, /* Collection (Physical), */ - 0x09, 0x42, /* Usage (Tip Switch), */ - 0x09, 0x44, /* Usage (Barrel Switch), */ - 0x09, 0x46, /* Usage (Tablet Pick), */ - 0x15, 0x01, /* Logical Minimum (1), */ - 0x25, 0x03, /* Logical Maximum (3), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x80, /* Input, */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0x32, /* Usage (In Range), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x01, /* Report Count (1), */ - 0x14, /* Logical Minimum (0), */ - 0xA4, /* Push, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x65, 0x13, /* Unit (Inch), */ - 0x55, 0xFD, /* Unit Exponent (-3), */ - 0x34, /* Physical Minimum (0), */ - 0x09, 0x30, /* Usage (X), */ - 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */ - 0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (Y), */ - 0x46, 0x52, 0x1C, /* Physical Maximum (7250), */ - 0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */ - 0x81, 0x02, /* Input (Variable), */ - 0xB4, /* Pop, */ - 0x09, 0x30, /* Usage (Tip Pressure), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x02, /* Usage (Mouse), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x01, /* Report ID (1), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA0, /* Collection (Physical), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x95, 0x02, /* Report Count (2), */ - 0x15, 0xFF, /* Logical Minimum (-1), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x09, 0x38, /* Usage (Wheel), */ - 0x0B, 0x38, 0x02, /* Usage (Consumer AC Pan), */ - 0x0C, 0x00, - 0x81, 0x06, /* Input (Variable, Relative), */ - 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x0C, /* Usage Page (Consumer), */ - 0x09, 0x01, /* Usage (Consumer Control), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x0D, /* Report ID (13), */ - 0x95, 0x01, /* Report Count (1), */ - 0x75, 0x10, /* Report Size (16), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */ - 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ - 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ - 0x09, 0xB6, /* Usage (Scan Previous Track), */ - 0x09, 0xB5, /* Usage (Scan Next Track), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x08, /* Usage (00h), */ - 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ - 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ - 0x15, 0x0C, /* Logical Minimum (12), */ - 0x25, 0x17, /* Logical Maximum (23), */ - 0x75, 0x05, /* Report Size (5), */ - 0x80, /* Input, */ - 0x75, 0x03, /* Report Size (3), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x20, /* Report Size (32), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0xC0, /* End Collection, */ - 0x09, 0x01, /* Usage (Consumer Control), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x0C, /* Report ID (12), */ - 0x75, 0x01, /* Report Size (1), */ - 0x09, 0xE9, /* Usage (Volume Inc), */ - 0x09, 0xEA, /* Usage (Volume Dec), */ - 0x09, 0xE2, /* Usage (Mute), */ - 0x14, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x06, /* Input (Variable, Relative), */ - 0x75, 0x05, /* Report Size (5), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0xC0 /* End Collection */ -}; - -static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - switch (hdev->product) { - case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH: - if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) { - rdesc = slim_tablet_5_8_inch_rdesc_fixed; - *rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed); - } - break; - case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH: - if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) { - rdesc = slim_tablet_12_1_inch_rdesc_fixed; - *rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed); - } - break; - case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH: - if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) { - rdesc = media_tablet_10_6_inch_rdesc_fixed; - *rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed); - } - break; - case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH: - if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) { - rdesc = media_tablet_14_1_inch_rdesc_fixed; - *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed); - } - break; - } - return rdesc; -} - -static const struct hid_device_id waltop_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, - USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, - USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, - USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, - USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, - { } -}; -MODULE_DEVICE_TABLE(hid, waltop_devices); - -static struct hid_driver waltop_driver = { - .name = "waltop", - .id_table = waltop_devices, - .report_fixup = waltop_report_fixup, -}; - -static int __init waltop_init(void) -{ - return hid_register_driver(&waltop_driver); -} - -static void __exit waltop_exit(void) -{ - hid_unregister_driver(&waltop_driver); -} - -module_init(waltop_init); -module_exit(waltop_exit); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/hid/hid-zydacron.c b/trunk/drivers/hid/hid-zydacron.c index aac1f9273149..9e8d35a203e4 100644 --- a/trunk/drivers/hid/hid-zydacron.c +++ b/trunk/drivers/hid/hid-zydacron.c @@ -27,10 +27,10 @@ struct zc_device { * Zydacron remote control has an invalid HID report descriptor, * that needs fixing before we can parse it. */ -static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) { - if (*rsize >= 253 && + if (rsize >= 253 && rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff && rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff && rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) { @@ -40,7 +40,6 @@ static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c; rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00; } - return rdesc; } #define zc_map_key_clear(c) \ diff --git a/trunk/drivers/hid/hidraw.c b/trunk/drivers/hid/hidraw.c index 8a4b32dca9f7..925992f549f0 100644 --- a/trunk/drivers/hid/hidraw.c +++ b/trunk/drivers/hid/hidraw.c @@ -218,13 +218,9 @@ static int hidraw_release(struct inode * inode, struct file * file) unsigned int minor = iminor(inode); struct hidraw *dev; struct hidraw_list *list = file->private_data; - int ret; - mutex_lock(&minors_lock); - if (!hidraw_table[minor]) { - ret = -ENODEV; - goto unlock; - } + if (!hidraw_table[minor]) + return -ENODEV; list_del(&list->node); dev = hidraw_table[minor]; @@ -237,12 +233,10 @@ static int hidraw_release(struct inode * inode, struct file * file) kfree(list->hidraw); } } + kfree(list); - ret = 0; -unlock: - mutex_unlock(&minors_lock); - return ret; + return 0; } static long hidraw_ioctl(struct file *file, unsigned int cmd, diff --git a/trunk/drivers/hid/usbhid/hid-core.c b/trunk/drivers/hid/usbhid/hid-core.c index 5489eab3a6bd..599041a7f670 100644 --- a/trunk/drivers/hid/usbhid/hid-core.c +++ b/trunk/drivers/hid/usbhid/hid-core.c @@ -807,10 +807,9 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co struct usb_host_interface *interface = intf->cur_altsetting; int ret; - if (usbhid->urbout && report_type != HID_FEATURE_REPORT) { + if (usbhid->urbout) { int actual_length; int skipped_report_id = 0; - if (buf[0] == 0x0) { /* Don't send the Report ID */ buf++; @@ -1470,6 +1469,9 @@ static int __init hid_init(void) retval = usbhid_quirks_init(quirks_param); if (retval) goto usbhid_quirks_init_fail; + retval = hiddev_init(); + if (retval) + goto hiddev_init_fail; retval = usb_register(&hid_driver); if (retval) goto usb_register_fail; @@ -1477,6 +1479,8 @@ static int __init hid_init(void) return 0; usb_register_fail: + hiddev_exit(); +hiddev_init_fail: usbhid_quirks_exit(); usbhid_quirks_init_fail: hid_unregister_driver(&hid_usb_driver); @@ -1489,6 +1493,7 @@ static int __init hid_init(void) static void __exit hid_exit(void) { usb_deregister(&hid_driver); + hiddev_exit(); usbhid_quirks_exit(); hid_unregister_driver(&hid_usb_driver); destroy_workqueue(resumption_waker); diff --git a/trunk/drivers/hid/usbhid/hid-quirks.c b/trunk/drivers/hid/usbhid/hid-quirks.c index 2c185477eeb3..f0260c699adb 100644 --- a/trunk/drivers/hid/usbhid/hid-quirks.c +++ b/trunk/drivers/hid/usbhid/hid-quirks.c @@ -34,6 +34,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, + { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, @@ -62,7 +63,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, @@ -72,10 +72,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, diff --git a/trunk/drivers/hid/usbhid/hiddev.c b/trunk/drivers/hid/usbhid/hiddev.c index fedd88df9a18..dfcb27613ec5 100644 --- a/trunk/drivers/hid/usbhid/hiddev.c +++ b/trunk/drivers/hid/usbhid/hiddev.c @@ -67,6 +67,8 @@ struct hiddev_list { struct mutex thread_lock; }; +static struct usb_driver hiddev_driver; + /* * Find a report, given the report's type and ID. The ID can be specified * indirectly by REPORT_ID_FIRST (which returns the first report of the given @@ -924,3 +926,41 @@ void hiddev_disconnect(struct hid_device *hid) kfree(hiddev); } } + +/* Currently this driver is a USB driver. It's not a conventional one in + * the sense that it doesn't probe at the USB level. Instead it waits to + * be connected by HID through the hiddev_connect / hiddev_disconnect + * routines. The reason to register as a USB device is to gain part of the + * minor number space from the USB major. + * + * In theory, should the HID code be generalized to more than one physical + * medium (say, IEEE 1384), this driver will probably need to register its + * own major number, and in doing so, no longer need to register with USB. + * At that point the probe routine and hiddev_driver struct below will no + * longer be useful. + */ + + +/* We never attach in this manner, and rely on HID to connect us. This + * is why there is no disconnect routine defined in the usb_driver either. + */ +static int hiddev_usbd_probe(struct usb_interface *intf, + const struct usb_device_id *hiddev_info) +{ + return -ENODEV; +} + +static /* const */ struct usb_driver hiddev_driver = { + .name = "hiddev", + .probe = hiddev_usbd_probe, +}; + +int __init hiddev_init(void) +{ + return usb_register(&hiddev_driver); +} + +void hiddev_exit(void) +{ + usb_deregister(&hiddev_driver); +} diff --git a/trunk/drivers/hwmon/adm1025.c b/trunk/drivers/hwmon/adm1025.c index 60befc0ee65f..251b63165e2a 100644 --- a/trunk/drivers/hwmon/adm1025.c +++ b/trunk/drivers/hwmon/adm1025.c @@ -12,7 +12,7 @@ * resolution of about 0.5% of the nominal value). Temperature values are * reported with a 1 deg resolution and a 3 deg accuracy. Complete * datasheet can be obtained from Analog's website at: - * http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 + * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html * * This driver also supports the ADM1025A, which differs from the ADM1025 * only in that it has "open-drain VID inputs while the ADM1025 has diff --git a/trunk/drivers/hwmon/adm1026.c b/trunk/drivers/hwmon/adm1026.c index 4bf969c0a32b..65335b268fa9 100644 --- a/trunk/drivers/hwmon/adm1026.c +++ b/trunk/drivers/hwmon/adm1026.c @@ -6,7 +6,7 @@ Chip details at: - + 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 diff --git a/trunk/drivers/hwmon/f75375s.c b/trunk/drivers/hwmon/f75375s.c index 95cbfb3a7077..9638d58f99fd 100644 --- a/trunk/drivers/hwmon/f75375s.c +++ b/trunk/drivers/hwmon/f75375s.c @@ -6,10 +6,10 @@ * Datasheets available at: * * f75375: - * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf + * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf * * f75373: - * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf + * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf * * 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 diff --git a/trunk/drivers/hwmon/g760a.c b/trunk/drivers/hwmon/g760a.c index 1d6a6fa31fb4..1f63d1a3af5e 100644 --- a/trunk/drivers/hwmon/g760a.c +++ b/trunk/drivers/hwmon/g760a.c @@ -5,7 +5,7 @@ Copyright (C) 2007 Herbert Valerio Riedel Complete datasheet is available at GMT's website: - http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf + http://www.gmt.com.tw/datasheet/g760a.pdf 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 diff --git a/trunk/drivers/hwmon/hwmon-vid.c b/trunk/drivers/hwmon/hwmon-vid.c index 2b2ca1694f95..bf0862a803c0 100644 --- a/trunk/drivers/hwmon/hwmon-vid.c +++ b/trunk/drivers/hwmon/hwmon-vid.c @@ -38,7 +38,7 @@ * available at http://developer.intel.com/. * * AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094, - * http://support.amd.com/us/Processor_TechDocs/26094.PDF + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF * Table 74. VID Code Voltages * This corresponds to an arbitrary VRM code of 24 in the functions below. * These CPU models (K8 revision <= E) have 5 VID pins. See also: diff --git a/trunk/drivers/i2c/Kconfig b/trunk/drivers/i2c/Kconfig index b923074b2cbe..30f06e956bfb 100644 --- a/trunk/drivers/i2c/Kconfig +++ b/trunk/drivers/i2c/Kconfig @@ -75,8 +75,7 @@ config I2C_HELPER_AUTO In doubt, say Y. config I2C_SMBUS - tristate - prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO + tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO help Say Y here if you want support for SMBus extensions to the I2C specification. At the moment, the only supported extension is diff --git a/trunk/drivers/i2c/Makefile b/trunk/drivers/i2c/Makefile index 23ac61e2db39..c00fd66388f5 100644 --- a/trunk/drivers/i2c/Makefile +++ b/trunk/drivers/i2c/Makefile @@ -9,4 +9,6 @@ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o obj-y += algos/ busses/ muxes/ -ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG +ifeq ($(CONFIG_I2C_DEBUG_CORE),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/trunk/drivers/i2c/algos/Kconfig b/trunk/drivers/i2c/algos/Kconfig index 3998dd620a03..7b2ce4a08524 100644 --- a/trunk/drivers/i2c/algos/Kconfig +++ b/trunk/drivers/i2c/algos/Kconfig @@ -15,15 +15,3 @@ config I2C_ALGOPCA tristate "I2C PCA 9564 interfaces" endmenu - -# In automatic configuration mode, we still have to define the -# symbols to avoid unmet dependencies. - -if I2C_HELPER_AUTO -config I2C_ALGOBIT - tristate -config I2C_ALGOPCF - tristate -config I2C_ALGOPCA - tristate -endif diff --git a/trunk/drivers/i2c/algos/Makefile b/trunk/drivers/i2c/algos/Makefile index 215303f60d61..18b3e962ec09 100644 --- a/trunk/drivers/i2c/algos/Makefile +++ b/trunk/drivers/i2c/algos/Makefile @@ -6,4 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o -ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG +ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/trunk/drivers/i2c/busses/Makefile b/trunk/drivers/i2c/busses/Makefile index 033ad413f328..c3ef49230cba 100644 --- a/trunk/drivers/i2c/busses/Makefile +++ b/trunk/drivers/i2c/busses/Makefile @@ -76,4 +76,6 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o -ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG +ifeq ($(CONFIG_I2C_DEBUG_BUS),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/trunk/drivers/i2c/busses/i2c-amd8111.c b/trunk/drivers/i2c/busses/i2c-amd8111.c index 6b6a6b1d7025..af1e5e254b7b 100644 --- a/trunk/drivers/i2c/busses/i2c-amd8111.c +++ b/trunk/drivers/i2c/busses/i2c-amd8111.c @@ -69,7 +69,7 @@ static struct pci_driver amd8111_driver; * ACPI 2.0 chapter 13 access of registers of the EC */ -static int amd_ec_wait_write(struct amd_smbus *smbus) +static unsigned int amd_ec_wait_write(struct amd_smbus *smbus) { int timeout = 500; @@ -85,7 +85,7 @@ static int amd_ec_wait_write(struct amd_smbus *smbus) return 0; } -static int amd_ec_wait_read(struct amd_smbus *smbus) +static unsigned int amd_ec_wait_read(struct amd_smbus *smbus) { int timeout = 500; @@ -101,7 +101,7 @@ static int amd_ec_wait_read(struct amd_smbus *smbus) return 0; } -static int amd_ec_read(struct amd_smbus *smbus, unsigned char address, +static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) { int status; @@ -124,7 +124,7 @@ static int amd_ec_read(struct amd_smbus *smbus, unsigned char address, return 0; } -static int amd_ec_write(struct amd_smbus *smbus, unsigned char address, +static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) { int status; @@ -196,7 +196,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, { struct amd_smbus *smbus = adap->algo_data; unsigned char protocol, len, pec, temp[2]; - int i, status; + int i; protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; @@ -209,62 +209,38 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, break; case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) { - status = amd_ec_write(smbus, AMD_SMB_CMD, - command); - if (status) - return status; - } + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_CMD, command); protocol |= AMD_SMB_PRTCL_BYTE; break; case I2C_SMBUS_BYTE_DATA: - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; - if (read_write == I2C_SMBUS_WRITE) { - status = amd_ec_write(smbus, AMD_SMB_DATA, - data->byte); - if (status) - return status; - } + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_DATA, data->byte); protocol |= AMD_SMB_PRTCL_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { - status = amd_ec_write(smbus, AMD_SMB_DATA, - data->word & 0xff); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_DATA + 1, - data->word >> 8); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_DATA, + data->word & 0xff); + amd_ec_write(smbus, AMD_SMB_DATA + 1, + data->word >> 8); } protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; break; case I2C_SMBUS_BLOCK_DATA: - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); - status = amd_ec_write(smbus, AMD_SMB_BCNT, len); - if (status) - return status; - for (i = 0; i < len; i++) { - status = - amd_ec_write(smbus, AMD_SMB_DATA + i, - data->block[i + 1]); - if (status) - return status; - } + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); } protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; break; @@ -272,35 +248,19 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_I2C_BLOCK_DATA: len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_BCNT, len); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); if (read_write == I2C_SMBUS_WRITE) - for (i = 0; i < len; i++) { - status = - amd_ec_write(smbus, AMD_SMB_DATA + i, - data->block[i + 1]); - if (status) - return status; - } + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; break; case I2C_SMBUS_PROC_CALL: - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_DATA, - data->word & 0xff); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_DATA + 1, - data->word >> 8); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff); + amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); protocol = AMD_SMB_PRTCL_PROC_CALL | pec; read_write = I2C_SMBUS_READ; break; @@ -308,18 +268,11 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_BLOCK_PROC_CALL: len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1); - status = amd_ec_write(smbus, AMD_SMB_CMD, command); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_BCNT, len); - if (status) - return status; - for (i = 0; i < len; i++) { - status = amd_ec_write(smbus, AMD_SMB_DATA + i, - data->block[i + 1]); - if (status) - return status; - } + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; read_write = I2C_SMBUS_READ; break; @@ -329,29 +282,24 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, return -EOPNOTSUPP; } - status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1); - if (status) - return status; - status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol); - if (status) - return status; + amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1); + amd_ec_write(smbus, AMD_SMB_PRTCL, protocol); - status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - if (status) - return status; + /* FIXME this discards status from ec_read(); so temp[0] will + * hold stack garbage ... the rest of this routine will act + * nonsensically. Ignored ec_write() status might explain + * some such failures... + */ + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); if (~temp[0] & AMD_SMB_STS_DONE) { udelay(500); - status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - if (status) - return status; + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); } if (~temp[0] & AMD_SMB_STS_DONE) { msleep(1); - status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - if (status) - return status; + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); } if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS)) @@ -363,35 +311,24 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, switch (size) { case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: - status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); - if (status) - return status; + amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); break; case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: - status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0); - if (status) - return status; - status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1); - if (status) - return status; + amd_ec_read(smbus, AMD_SMB_DATA, temp + 0); + amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1); data->word = (temp[1] << 8) | temp[0]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: - status = amd_ec_read(smbus, AMD_SMB_BCNT, &len); - if (status) - return status; + amd_ec_read(smbus, AMD_SMB_BCNT, &len); len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); case I2C_SMBUS_I2C_BLOCK_DATA: - for (i = 0; i < len; i++) { - status = amd_ec_read(smbus, AMD_SMB_DATA + i, - data->block + i + 1); - if (status) - return status; - } + for (i = 0; i < len; i++) + amd_ec_read(smbus, AMD_SMB_DATA + i, + data->block + i + 1); data->block[0] = len; break; } diff --git a/trunk/drivers/i2c/busses/i2c-ibm_iic.c b/trunk/drivers/i2c/busses/i2c-ibm_iic.c index 6e3c38240336..89eedf45d30e 100644 --- a/trunk/drivers/i2c/busses/i2c-ibm_iic.c +++ b/trunk/drivers/i2c/busses/i2c-ibm_iic.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-nuc900.c b/trunk/drivers/i2c/busses/i2c-nuc900.c index 72434263787b..92d770d7bbc2 100644 --- a/trunk/drivers/i2c/busses/i2c-nuc900.c +++ b/trunk/drivers/i2c/busses/i2c-nuc900.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-pca-platform.c b/trunk/drivers/i2c/busses/i2c-pca-platform.c index ace67995d7de..5f6d7f89e225 100644 --- a/trunk/drivers/i2c/busses/i2c-pca-platform.c +++ b/trunk/drivers/i2c/busses/i2c-pca-platform.c @@ -224,7 +224,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) if (irq) { ret = request_irq(irq, i2c_pca_pf_handler, - IRQF_TRIGGER_FALLING, pdev->name, i2c); + IRQF_TRIGGER_FALLING, i2c->adap.name, i2c); if (ret) goto e_reqirq; } diff --git a/trunk/drivers/i2c/busses/i2c-pxa.c b/trunk/drivers/i2c/busses/i2c-pxa.c index f4c19a97e0b3..c94e51b2651e 100644 --- a/trunk/drivers/i2c/busses/i2c-pxa.c +++ b/trunk/drivers/i2c/busses/i2c-pxa.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-s3c2410.c b/trunk/drivers/i2c/busses/i2c-s3c2410.c index 6a292ea5e35c..bf831bf81587 100644 --- a/trunk/drivers/i2c/busses/i2c-s3c2410.c +++ b/trunk/drivers/i2c/busses/i2c-s3c2410.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-viapro.c b/trunk/drivers/i2c/busses/i2c-viapro.c index 0b012f1f8ac5..4c6fff5f330d 100644 --- a/trunk/drivers/i2c/busses/i2c-viapro.c +++ b/trunk/drivers/i2c/busses/i2c-viapro.c @@ -185,8 +185,14 @@ static int vt596_transaction(u8 size) } if (temp & 0x04) { + int read = inb_p(SMBHSTADD) & 0x01; result = -ENXIO; - dev_dbg(&vt596_adapter.dev, "No response\n"); + /* The quick and receive byte commands are used to probe + for chips, so errors are expected, and we don't want + to frighten the user. */ + if (!((size == VT596_QUICK && !read) || + (size == VT596_BYTE && read))) + dev_err(&vt596_adapter.dev, "Transaction error!\n"); } /* Resetting status register */ diff --git a/trunk/drivers/i2c/i2c-core.c b/trunk/drivers/i2c/i2c-core.c index d231f683f576..bea4c5021d26 100644 --- a/trunk/drivers/i2c/i2c-core.c +++ b/trunk/drivers/i2c/i2c-core.c @@ -425,14 +425,14 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp) /* walk up mux tree */ static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result; result = device_for_each_child(&adapter->dev, &addr, __i2c_check_addr_busy); - if (!result && parent) - result = i2c_check_mux_parents(parent, addr); + if (!result && i2c_parent_is_i2c_adapter(adapter)) + result = i2c_check_mux_parents( + to_i2c_adapter(adapter->dev.parent), addr); return result; } @@ -453,11 +453,11 @@ static int i2c_check_mux_children(struct device *dev, void *addrp) static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result = 0; - if (parent) - result = i2c_check_mux_parents(parent, addr); + if (i2c_parent_is_i2c_adapter(adapter)) + result = i2c_check_mux_parents( + to_i2c_adapter(adapter->dev.parent), addr); if (!result) result = device_for_each_child(&adapter->dev, &addr, @@ -472,10 +472,8 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) */ void i2c_lock_adapter(struct i2c_adapter *adapter) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - i2c_lock_adapter(parent); + if (i2c_parent_is_i2c_adapter(adapter)) + i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent)); else rt_mutex_lock(&adapter->bus_lock); } @@ -487,10 +485,8 @@ EXPORT_SYMBOL_GPL(i2c_lock_adapter); */ static int i2c_trylock_adapter(struct i2c_adapter *adapter) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - return i2c_trylock_adapter(parent); + if (i2c_parent_is_i2c_adapter(adapter)) + return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent)); else return rt_mutex_trylock(&adapter->bus_lock); } @@ -501,10 +497,8 @@ static int i2c_trylock_adapter(struct i2c_adapter *adapter) */ void i2c_unlock_adapter(struct i2c_adapter *adapter) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - i2c_unlock_adapter(parent); + if (i2c_parent_is_i2c_adapter(adapter)) + i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent)); else rt_mutex_unlock(&adapter->bus_lock); } @@ -683,6 +677,8 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, char *blank, end; int res; + dev_warn(dev, "The new_device interface is still experimental " + "and may change in a near future\n"); memset(&info, 0, sizeof(struct i2c_board_info)); blank = strchr(buf, ' '); @@ -1508,25 +1504,26 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) if (!driver->detect || !address_list) return 0; - /* Stop here if the classes do not match */ - if (!(adapter->class & driver->class)) - return 0; - /* Set up a temporary client to help detect callback */ temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!temp_client) return -ENOMEM; temp_client->adapter = adapter; + /* Stop here if the classes do not match */ + if (!(adapter->class & driver->class)) + goto exit_free; + for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { dev_dbg(&adapter->dev, "found normal entry for adapter %d, " "addr 0x%02x\n", adap_id, address_list[i]); temp_client->addr = address_list[i]; err = i2c_detect_address(temp_client, driver); - if (unlikely(err)) - break; + if (err) + goto exit_free; } + exit_free: kfree(temp_client); return err; } diff --git a/trunk/drivers/i2c/i2c-dev.c b/trunk/drivers/i2c/i2c-dev.c index cec0f3ba97f8..5f3a52d517c3 100644 --- a/trunk/drivers/i2c/i2c-dev.c +++ b/trunk/drivers/i2c/i2c-dev.c @@ -192,12 +192,13 @@ static int i2cdev_check(struct device *dev, void *addrp) /* walk up mux tree */ static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result; result = device_for_each_child(&adapter->dev, &addr, i2cdev_check); - if (!result && parent) - result = i2cdev_check_mux_parents(parent, addr); + + if (!result && i2c_parent_is_i2c_adapter(adapter)) + result = i2cdev_check_mux_parents( + to_i2c_adapter(adapter->dev.parent), addr); return result; } @@ -221,11 +222,11 @@ static int i2cdev_check_mux_children(struct device *dev, void *addrp) driver bound to it, as NOT busy. */ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result = 0; - if (parent) - result = i2cdev_check_mux_parents(parent, addr); + if (i2c_parent_is_i2c_adapter(adapter)) + result = i2cdev_check_mux_parents( + to_i2c_adapter(adapter->dev.parent), addr); if (!result) result = device_for_each_child(&adapter->dev, &addr, diff --git a/trunk/drivers/i2c/muxes/Kconfig b/trunk/drivers/i2c/muxes/Kconfig index 4d91d80bfd23..4c9a99c4fcb0 100644 --- a/trunk/drivers/i2c/muxes/Kconfig +++ b/trunk/drivers/i2c/muxes/Kconfig @@ -5,16 +5,6 @@ menu "Multiplexer I2C Chip support" depends on I2C_MUX -config I2C_MUX_PCA9541 - tristate "NXP PCA9541 I2C Master Selector" - depends on EXPERIMENTAL - help - If you say yes here you get support for the NXP PCA9541 - I2C Master Selector. - - This driver can also be built as a module. If so, the module - will be called pca9541. - config I2C_MUX_PCA954x tristate "Philips PCA954x I2C Mux/switches" depends on EXPERIMENTAL diff --git a/trunk/drivers/i2c/muxes/Makefile b/trunk/drivers/i2c/muxes/Makefile index d743806d9b42..bd83b5274815 100644 --- a/trunk/drivers/i2c/muxes/Makefile +++ b/trunk/drivers/i2c/muxes/Makefile @@ -1,7 +1,8 @@ # # Makefile for multiplexer I2C chip drivers. -obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o -ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG +ifeq ($(CONFIG_I2C_DEBUG_BUS),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/trunk/drivers/i2c/muxes/pca9541.c b/trunk/drivers/i2c/muxes/pca9541.c deleted file mode 100644 index ed699c5aa79d..000000000000 --- a/trunk/drivers/i2c/muxes/pca9541.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * I2C multiplexer driver for PCA9541 bus master selector - * - * Copyright (c) 2010 Ericsson AB. - * - * Author: Guenter Roeck - * - * Derived from: - * pca954x.c - * - * Copyright (c) 2008-2009 Rodolfo Giometti - * Copyright (c) 2008-2009 Eurotech S.p.A. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * The PCA9541 is a bus master selector. It supports two I2C masters connected - * to a single slave bus. - * - * Before each bus transaction, a master has to acquire bus ownership. After the - * transaction is complete, bus ownership has to be released. This fits well - * into the I2C multiplexer framework, which provides select and release - * functions for this purpose. For this reason, this driver is modeled as - * single-channel I2C bus multiplexer. - * - * This driver assumes that the two bus masters are controlled by two different - * hosts. If a single host controls both masters, platform code has to ensure - * that only one of the masters is instantiated at any given time. - */ - -#define PCA9541_CONTROL 0x01 -#define PCA9541_ISTAT 0x02 - -#define PCA9541_CTL_MYBUS (1 << 0) -#define PCA9541_CTL_NMYBUS (1 << 1) -#define PCA9541_CTL_BUSON (1 << 2) -#define PCA9541_CTL_NBUSON (1 << 3) -#define PCA9541_CTL_BUSINIT (1 << 4) -#define PCA9541_CTL_TESTON (1 << 6) -#define PCA9541_CTL_NTESTON (1 << 7) - -#define PCA9541_ISTAT_INTIN (1 << 0) -#define PCA9541_ISTAT_BUSINIT (1 << 1) -#define PCA9541_ISTAT_BUSOK (1 << 2) -#define PCA9541_ISTAT_BUSLOST (1 << 3) -#define PCA9541_ISTAT_MYTEST (1 << 6) -#define PCA9541_ISTAT_NMYTEST (1 << 7) - -#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) -#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) -#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) -#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) - -/* arbitration timeouts, in jiffies */ -#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ -#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ - -/* arbitration retry delays, in us */ -#define SELECT_DELAY_SHORT 50 -#define SELECT_DELAY_LONG 1000 - -struct pca9541 { - struct i2c_adapter *mux_adap; - unsigned long select_timeout; - unsigned long arb_timeout; -}; - -static const struct i2c_device_id pca9541_id[] = { - {"pca9541", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, pca9541_id); - -/* - * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() - * as they will try to lock the adapter a second time. - */ -static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) -{ - struct i2c_adapter *adap = client->adapter; - int ret; - - if (adap->algo->master_xfer) { - struct i2c_msg msg; - char buf[2]; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2; - buf[0] = command; - buf[1] = val; - msg.buf = buf; - ret = adap->algo->master_xfer(adap, &msg, 1); - } else { - union i2c_smbus_data data; - - data.byte = val; - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, - I2C_SMBUS_WRITE, - command, - I2C_SMBUS_BYTE_DATA, &data); - } - - return ret; -} - -/* - * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() - * as they will try to lock adapter a second time. - */ -static int pca9541_reg_read(struct i2c_client *client, u8 command) -{ - struct i2c_adapter *adap = client->adapter; - int ret; - u8 val; - - if (adap->algo->master_xfer) { - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &command - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = &val - } - }; - ret = adap->algo->master_xfer(adap, msg, 2); - if (ret == 2) - ret = val; - else if (ret >= 0) - ret = -EIO; - } else { - union i2c_smbus_data data; - - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, - I2C_SMBUS_READ, - command, - I2C_SMBUS_BYTE_DATA, &data); - if (!ret) - ret = data.byte; - } - return ret; -} - -/* - * Arbitration management functions - */ - -/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ -static void pca9541_release_bus(struct i2c_client *client) -{ - int reg; - - reg = pca9541_reg_read(client, PCA9541_CONTROL); - if (reg >= 0 && !busoff(reg) && mybus(reg)) - pca9541_reg_write(client, PCA9541_CONTROL, - (reg & PCA9541_CTL_NBUSON) >> 1); -} - -/* - * Arbitration is defined as a two-step process. A bus master can only activate - * the slave bus if it owns it; otherwise it has to request ownership first. - * This multi-step process ensures that access contention is resolved - * gracefully. - * - * Bus Ownership Other master Action - * state requested access - * ---------------------------------------------------- - * off - yes wait for arbitration timeout or - * for other master to drop request - * off no no take ownership - * off yes no turn on bus - * on yes - done - * on no - wait for arbitration timeout or - * for other master to release bus - * - * The main contention point occurs if the slave bus is off and both masters - * request ownership at the same time. In this case, one master will turn on - * the slave bus, believing that it owns it. The other master will request - * bus ownership. Result is that the bus is turned on, and master which did - * _not_ own the slave bus before ends up owning it. - */ - -/* Control commands per PCA9541 datasheet */ -static const u8 pca9541_control[16] = { - 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 -}; - -/* - * Channel arbitration - * - * Return values: - * <0: error - * 0 : bus not acquired - * 1 : bus acquired - */ -static int pca9541_arbitrate(struct i2c_client *client) -{ - struct pca9541 *data = i2c_get_clientdata(client); - int reg; - - reg = pca9541_reg_read(client, PCA9541_CONTROL); - if (reg < 0) - return reg; - - if (busoff(reg)) { - int istat; - /* - * Bus is off. Request ownership or turn it on unless - * other master requested ownership. - */ - istat = pca9541_reg_read(client, PCA9541_ISTAT); - if (!(istat & PCA9541_ISTAT_NMYTEST) - || time_is_before_eq_jiffies(data->arb_timeout)) { - /* - * Other master did not request ownership, - * or arbitration timeout expired. Take the bus. - */ - pca9541_reg_write(client, - PCA9541_CONTROL, - pca9541_control[reg & 0x0f] - | PCA9541_CTL_NTESTON); - data->select_timeout = SELECT_DELAY_SHORT; - } else { - /* - * Other master requested ownership. - * Set extra long timeout to give it time to acquire it. - */ - data->select_timeout = SELECT_DELAY_LONG * 2; - } - } else if (mybus(reg)) { - /* - * Bus is on, and we own it. We are done with acquisition. - * Reset NTESTON and BUSINIT, then return success. - */ - if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) - pca9541_reg_write(client, - PCA9541_CONTROL, - reg & ~(PCA9541_CTL_NTESTON - | PCA9541_CTL_BUSINIT)); - return 1; - } else { - /* - * Other master owns the bus. - * If arbitration timeout has expired, force ownership. - * Otherwise request it. - */ - data->select_timeout = SELECT_DELAY_LONG; - if (time_is_before_eq_jiffies(data->arb_timeout)) { - /* Time is up, take the bus and reset it. */ - pca9541_reg_write(client, - PCA9541_CONTROL, - pca9541_control[reg & 0x0f] - | PCA9541_CTL_BUSINIT - | PCA9541_CTL_NTESTON); - } else { - /* Request bus ownership if needed */ - if (!(reg & PCA9541_CTL_NTESTON)) - pca9541_reg_write(client, - PCA9541_CONTROL, - reg | PCA9541_CTL_NTESTON); - } - } - return 0; -} - -static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan) -{ - struct pca9541 *data = i2c_get_clientdata(client); - int ret; - unsigned long timeout = jiffies + ARB2_TIMEOUT; - /* give up after this time */ - - data->arb_timeout = jiffies + ARB_TIMEOUT; - /* force bus ownership after this time */ - - do { - ret = pca9541_arbitrate(client); - if (ret) - return ret < 0 ? ret : 0; - - if (data->select_timeout == SELECT_DELAY_SHORT) - udelay(data->select_timeout); - else - msleep(data->select_timeout / 1000); - } while (time_is_after_eq_jiffies(timeout)); - - return -ETIMEDOUT; -} - -static int pca9541_release_chan(struct i2c_adapter *adap, - void *client, u32 chan) -{ - pca9541_release_bus(client); - return 0; -} - -/* - * I2C init/probing/exit functions - */ -static int pca9541_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adap = client->adapter; - struct pca954x_platform_data *pdata = client->dev.platform_data; - struct pca9541 *data; - int force; - int ret = -ENODEV; - - if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) - goto err; - - data = kzalloc(sizeof(struct pca9541), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto err; - } - - i2c_set_clientdata(client, data); - - /* - * I2C accesses are unprotected here. - * We have to lock the adapter before releasing the bus. - */ - i2c_lock_adapter(adap); - pca9541_release_bus(client); - i2c_unlock_adapter(adap); - - /* Create mux adapter */ - - force = 0; - if (pdata) - force = pdata->modes[0].adap_id; - data->mux_adap = i2c_add_mux_adapter(adap, client, force, 0, - pca9541_select_chan, - pca9541_release_chan); - - if (data->mux_adap == NULL) { - dev_err(&client->dev, "failed to register master selector\n"); - goto exit_free; - } - - dev_info(&client->dev, "registered master selector for I2C %s\n", - client->name); - - return 0; - -exit_free: - kfree(data); -err: - return ret; -} - -static int pca9541_remove(struct i2c_client *client) -{ - struct pca9541 *data = i2c_get_clientdata(client); - - i2c_del_mux_adapter(data->mux_adap); - - kfree(data); - return 0; -} - -static struct i2c_driver pca9541_driver = { - .driver = { - .name = "pca9541", - .owner = THIS_MODULE, - }, - .probe = pca9541_probe, - .remove = pca9541_remove, - .id_table = pca9541_id, -}; - -static int __init pca9541_init(void) -{ - return i2c_add_driver(&pca9541_driver); -} - -static void __exit pca9541_exit(void) -{ - i2c_del_driver(&pca9541_driver); -} - -module_init(pca9541_init); -module_exit(pca9541_exit); - -MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/i2c/muxes/pca954x.c b/trunk/drivers/i2c/muxes/pca954x.c index 54e1ce73534b..6f9accf3189d 100644 --- a/trunk/drivers/i2c/muxes/pca954x.c +++ b/trunk/drivers/i2c/muxes/pca954x.c @@ -181,8 +181,8 @@ static int pca954x_deselect_mux(struct i2c_adapter *adap, /* * I2C init/probing/exit functions */ -static int pca954x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int __devinit pca954x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = client->dev.platform_data; @@ -255,7 +255,7 @@ static int pca954x_probe(struct i2c_client *client, return ret; } -static int pca954x_remove(struct i2c_client *client) +static int __devexit pca954x_remove(struct i2c_client *client) { struct pca954x *data = i2c_get_clientdata(client); const struct chip_desc *chip = &chips[data->type]; @@ -279,7 +279,7 @@ static struct i2c_driver pca954x_driver = { .owner = THIS_MODULE, }, .probe = pca954x_probe, - .remove = pca954x_remove, + .remove = __devexit_p(pca954x_remove), .id_table = pca954x_id, }; diff --git a/trunk/drivers/ide/hpt366.c b/trunk/drivers/ide/hpt366.c index 97d98fbf5849..45163693f737 100644 --- a/trunk/drivers/ide/hpt366.c +++ b/trunk/drivers/ide/hpt366.c @@ -12,7 +12,7 @@ * * * HighPoint has its own drivers (open source except for the RAID part) - * available from http://www.highpoint-tech.com/USA_new/service_support.htm + * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/. * This may be useful to anyone wanting to work on this driver, however do not * trust them too much since the code tends to become less and less meaningful * as the time passes... :-/ diff --git a/trunk/drivers/ide/ht6560b.c b/trunk/drivers/ide/ht6560b.c index 808bcdcbf8e1..d81e49680c3f 100644 --- a/trunk/drivers/ide/ht6560b.c +++ b/trunk/drivers/ide/ht6560b.c @@ -10,6 +10,7 @@ * Author: Mikko Ala-Fossi * Jan Evert van Grootheest * + * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ #define DRV_NAME "ht6560b" diff --git a/trunk/drivers/ide/ide-disk.c b/trunk/drivers/ide/ide-disk.c index 274798068a54..7c5b01ce51d2 100644 --- a/trunk/drivers/ide/ide-disk.c +++ b/trunk/drivers/ide/ide-disk.c @@ -435,11 +435,12 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq) if (!(rq->cmd_flags & REQ_FLUSH)) return BLKPREP_OK; - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); /* FIXME: map struct ide_taskfile on rq->cmd[] */ BUG_ON(cmd == NULL); + memset(cmd, 0, sizeof(*cmd)); if (ata_id_flush_ext_enabled(drive->id) && (drive->capacity64 >= (1UL << 28))) cmd->tf.command = ATA_CMD_FLUSH_EXT; diff --git a/trunk/drivers/infiniband/Kconfig b/trunk/drivers/infiniband/Kconfig index 6e35eccc9caa..89d70de5e235 100644 --- a/trunk/drivers/infiniband/Kconfig +++ b/trunk/drivers/infiniband/Kconfig @@ -16,7 +16,7 @@ config INFINIBAND_USER_MAD Userspace InfiniBand Management Datagram (MAD) support. This is the kernel side of the userspace MAD support, which allows userspace processes to send and receive MADs. You will also - need libibumad from . + need libibumad from . config INFINIBAND_USER_ACCESS tristate "InfiniBand userspace access (verbs and CM)" @@ -28,7 +28,7 @@ config INFINIBAND_USER_ACCESS to set up connections and directly access InfiniBand hardware for fast-path operations. You will also need libibverbs, libibcm and a hardware driver library from - . + . config INFINIBAND_USER_MEM bool diff --git a/trunk/drivers/infiniband/hw/cxgb3/Kconfig b/trunk/drivers/infiniband/hw/cxgb3/Kconfig index 2b6352b85485..2acec3fadf69 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/Kconfig +++ b/trunk/drivers/infiniband/hw/cxgb3/Kconfig @@ -10,7 +10,7 @@ config INFINIBAND_CXGB3 our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . diff --git a/trunk/drivers/infiniband/hw/cxgb4/Kconfig b/trunk/drivers/infiniband/hw/cxgb4/Kconfig index 6b7e6c543534..ccb85eaaad75 100644 --- a/trunk/drivers/infiniband/hw/cxgb4/Kconfig +++ b/trunk/drivers/infiniband/hw/cxgb4/Kconfig @@ -10,7 +10,7 @@ config INFINIBAND_CXGB4 our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . diff --git a/trunk/drivers/infiniband/hw/qib/qib_file_ops.c b/trunk/drivers/infiniband/hw/qib/qib_file_ops.c index 79d9971aff1f..aa2be214270f 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/trunk/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1723,7 +1723,7 @@ static int qib_close(struct inode *in, struct file *fp) mutex_lock(&qib_mutex); - fd = fp->private_data; + fd = (struct qib_filedata *) fp->private_data; fp->private_data = NULL; rcd = fd->rcd; if (!rcd) { @@ -1809,7 +1809,7 @@ static int qib_ctxt_info(struct file *fp, struct qib_ctxt_info __user *uinfo) struct qib_ctxtdata *rcd = ctxt_fp(fp); struct qib_filedata *fd; - fd = fp->private_data; + fd = (struct qib_filedata *) fp->private_data; info.num_active = qib_count_active_units(); info.unit = rcd->dd->unit; diff --git a/trunk/drivers/infiniband/ulp/iser/Kconfig b/trunk/drivers/infiniband/ulp/iser/Kconfig index d00af71a2cfc..b411c51842da 100644 --- a/trunk/drivers/infiniband/ulp/iser/Kconfig +++ b/trunk/drivers/infiniband/ulp/iser/Kconfig @@ -9,4 +9,4 @@ config INFINIBAND_ISER The iSER protocol is defined by IETF. See - and + and diff --git a/trunk/drivers/input/joystick/gamecon.c b/trunk/drivers/input/joystick/gamecon.c index e68e49786483..0ffaf2c77a19 100644 --- a/trunk/drivers/input/joystick/gamecon.c +++ b/trunk/drivers/input/joystick/gamecon.c @@ -521,8 +521,9 @@ static void gc_multi_process_packet(struct gc *gc) * PSX support * * See documentation at: - * http://www.geocities.co.jp/Playtown/2004/psx/ps_eng.txt + * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt * http://www.gamesx.com/controldata/psxcont/psxcont.htm + * ftp://milano.usal.es/pablo/ * */ diff --git a/trunk/drivers/input/misc/cm109.c b/trunk/drivers/input/misc/cm109.c index b09c7d127219..2b0eba6619bd 100644 --- a/trunk/drivers/input/misc/cm109.c +++ b/trunk/drivers/input/misc/cm109.c @@ -259,7 +259,7 @@ static unsigned short keymap_usbph01(int scancode) /* * Keymap for ATCom AU-100 - * http://www.atcom.cn/products.html + * http://www.atcom.cn/En_products_AU100.html * http://www.packetizer.com/products/au100/ * http://www.voip-info.org/wiki/view/AU-100 * diff --git a/trunk/drivers/input/mouse/Kconfig b/trunk/drivers/input/mouse/Kconfig index bf5fd7f6a313..c714ca2407f8 100644 --- a/trunk/drivers/input/mouse/Kconfig +++ b/trunk/drivers/input/mouse/Kconfig @@ -30,7 +30,6 @@ config MOUSE_PS2 and a new version of GPM at: - to take advantage of the advanced features of the touchpad. If unsure, say Y. diff --git a/trunk/drivers/input/mouse/touchkit_ps2.c b/trunk/drivers/input/mouse/touchkit_ps2.c index 1fd8f5e192f9..88121c59c3cc 100644 --- a/trunk/drivers/input/mouse/touchkit_ps2.c +++ b/trunk/drivers/input/mouse/touchkit_ps2.c @@ -21,8 +21,8 @@ * * Based upon touchkitusb.c * - * Vendor documentation is available at: - * http://home.eeti.com.tw/web20/drivers/Software%20Programming%20Guide_v2.0.pdf + * Vendor documentation is available in support section of: + * http://www.egalax.com.tw/ */ #include diff --git a/trunk/drivers/input/touchscreen/mk712.c b/trunk/drivers/input/touchscreen/mk712.c index 36e57deacd03..efd3aebaba5f 100644 --- a/trunk/drivers/input/touchscreen/mk712.c +++ b/trunk/drivers/input/touchscreen/mk712.c @@ -17,7 +17,7 @@ * found in Gateway AOL Connected Touchpad computers. * * Documentation for ICS MK712 can be found at: - * http://www.idt.com/products/getDoc.cfm?docID=18713923 + * http://www.icst.com/pdf/mk712.pdf */ /* diff --git a/trunk/drivers/isdn/i4l/isdn_audio.c b/trunk/drivers/isdn/i4l/isdn_audio.c index d5013935ac62..861bdf3421f2 100644 --- a/trunk/drivers/isdn/i4l/isdn_audio.c +++ b/trunk/drivers/isdn/i4l/isdn_audio.c @@ -439,7 +439,7 @@ isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in, /* * Goertzel algorithm. - * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/ + * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/ * for more info. * Result is stored into an sk_buff and queued up for later * evaluation. diff --git a/trunk/drivers/macintosh/therm_adt746x.c b/trunk/drivers/macintosh/therm_adt746x.c index 9e3e2c566598..d0d221332db0 100644 --- a/trunk/drivers/macintosh/therm_adt746x.c +++ b/trunk/drivers/macintosh/therm_adt746x.c @@ -3,9 +3,9 @@ * * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt * - * Documentation from 115254175ADT7467_pra.pdf and 3686221171167ADT7460_b.pdf - * http://www.onsemi.com/PowerSolutions/product.do?id=ADT7467 - * http://www.onsemi.com/PowerSolutions/product.do?id=ADT7460 + * Documentation from + * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf + * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf * */ diff --git a/trunk/drivers/media/IR/keymaps/rc-manli.c b/trunk/drivers/media/IR/keymaps/rc-manli.c index 0f590b3d01c0..1e9fbfa90a1e 100644 --- a/trunk/drivers/media/IR/keymaps/rc-manli.c +++ b/trunk/drivers/media/IR/keymaps/rc-manli.c @@ -13,6 +13,7 @@ #include /* Michael Tokarev + http://www.corpit.ru/mjt/beholdTV/remote_control.jpg keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at least, and probably other cards too. The "ascii-art picture" below (in comments, first row diff --git a/trunk/drivers/media/dvb/ttpci/av7110.c b/trunk/drivers/media/dvb/ttpci/av7110.c index a12b88f53ed9..893fbc57c72f 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110.c +++ b/trunk/drivers/media/dvb/ttpci/av7110.c @@ -26,7 +26,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ @@ -2291,7 +2291,12 @@ static int frontend_init(struct av7110 *av7110) /* Budgetpatch note: * Original hardware design by Roberto Deza: * There is a DVB_Wiki at - * http://www.linuxtv.org/ + * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page + * where is described this 'DVB TT Budget Patch', on Card Modding: + * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch + * On the short description there is also a link to a external file, + * with more details: + * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip * * New software triggering design by Emard that works on * original Roberto Deza's hardware: diff --git a/trunk/drivers/media/dvb/ttpci/av7110_av.c b/trunk/drivers/media/dvb/ttpci/av7110_av.c index 244d5d51f5f9..6ef3996565ad 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_av.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_av.c @@ -25,7 +25,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include diff --git a/trunk/drivers/media/dvb/ttpci/av7110_ca.c b/trunk/drivers/media/dvb/ttpci/av7110_ca.c index 122c72806916..43f61f2eca98 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_ca.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_ca.c @@ -25,7 +25,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include diff --git a/trunk/drivers/media/dvb/ttpci/av7110_hw.c b/trunk/drivers/media/dvb/ttpci/av7110_hw.c index f1cbfe526989..e162691b515d 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_hw.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_hw.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ /* for debugging ARM communication: */ diff --git a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c index ac20c5bbfa43..8986d967d2f4 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include diff --git a/trunk/drivers/media/dvb/ttpci/budget-av.c b/trunk/drivers/media/dvb/ttpci/budget-av.c index 97afc01f60d0..983672aa2450 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-av.c +++ b/trunk/drivers/media/dvb/ttpci/budget-av.c @@ -30,7 +30,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include "budget.h" diff --git a/trunk/drivers/media/dvb/ttpci/budget-ci.c b/trunk/drivers/media/dvb/ttpci/budget-ci.c index a9c2c326df4b..13ac9e3ab121 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-ci.c +++ b/trunk/drivers/media/dvb/ttpci/budget-ci.c @@ -26,7 +26,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include diff --git a/trunk/drivers/media/dvb/ttpci/budget-core.c b/trunk/drivers/media/dvb/ttpci/budget-core.c index 054661315311..ba18e56d5f11 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-core.c +++ b/trunk/drivers/media/dvb/ttpci/budget-core.c @@ -31,7 +31,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ diff --git a/trunk/drivers/media/dvb/ttpci/budget-patch.c b/trunk/drivers/media/dvb/ttpci/budget-patch.c index 579835590690..9c92f9ddd223 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-patch.c +++ b/trunk/drivers/media/dvb/ttpci/budget-patch.c @@ -27,7 +27,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include "av7110.h" diff --git a/trunk/drivers/media/dvb/ttpci/budget.c b/trunk/drivers/media/dvb/ttpci/budget.c index d238fb9371a7..874a10a9d493 100644 --- a/trunk/drivers/media/dvb/ttpci/budget.c +++ b/trunk/drivers/media/dvb/ttpci/budget.c @@ -31,7 +31,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/dvb/ */ #include "budget.h" diff --git a/trunk/drivers/media/radio/radio-maxiradio.c b/trunk/drivers/media/radio/radio-maxiradio.c index 255d40df4b46..4349213b403b 100644 --- a/trunk/drivers/media/radio/radio-maxiradio.c +++ b/trunk/drivers/media/radio/radio-maxiradio.c @@ -13,7 +13,7 @@ * anybody does please mail me. * * For the pdf file see: - * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf + * http://www.semiconductors.philips.com/pip/TEA5757H/V1 * * * CHANGES: diff --git a/trunk/drivers/media/radio/radio-typhoon.c b/trunk/drivers/media/radio/radio-typhoon.c index b1f630527dc1..03439282dfce 100644 --- a/trunk/drivers/media/radio/radio-typhoon.c +++ b/trunk/drivers/media/radio/radio-typhoon.c @@ -1,6 +1,9 @@ /* Typhoon Radio Card driver for radio support * (c) 1999 Dr. Henrik Seidel * + * Card manufacturer: + * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e + * * Notes on the hardware * * This card has two output sockets, one for speakers and one for line. diff --git a/trunk/drivers/media/video/Kconfig b/trunk/drivers/media/video/Kconfig index d000522cb0f4..f6e4d0475351 100644 --- a/trunk/drivers/media/video/Kconfig +++ b/trunk/drivers/media/video/Kconfig @@ -978,7 +978,7 @@ config USB_STKWEBCAM Supported devices are typically found in some Asus laptops, with USB id 174f:a311 and 05e1:0501. Other Syntek cameras may be supported by the stk11xx driver, from which this is - derived, see + derived, see http://stk11xx.sourceforge.net To compile this driver as a module, choose M here: the module will be called stkwebcam. diff --git a/trunk/drivers/media/video/cafe_ccic.c b/trunk/drivers/media/video/cafe_ccic.c index 9536f1a40dd2..be35e6965829 100644 --- a/trunk/drivers/media/video/cafe_ccic.c +++ b/trunk/drivers/media/video/cafe_ccic.c @@ -4,7 +4,7 @@ * sensor. * * The data sheet for this device can be found at: - * http://www.marvell.com/products/pc_connectivity/88alp01/ + * http://www.marvell.com/products/pcconn/88ALP01.jsp * * Copyright 2006 One Laptop Per Child Association, Inc. * Copyright 2006-7 Jonathan Corbet diff --git a/trunk/drivers/media/video/cx18/cx18-cards.c b/trunk/drivers/media/video/cx18/cx18-cards.c index fe1090940b01..6b805afe5d20 100644 --- a/trunk/drivers/media/video/cx18/cx18-cards.c +++ b/trunk/drivers/media/video/cx18/cx18-cards.c @@ -39,7 +39,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { .tv = { 0x61, 0x60, I2C_CLIENT_END }, }; -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii This keeps the PCI ID database up to date. Note that the entries must be added under vendor 0x4444 (Conexant) as subsystem IDs. New vendor IDs should still be added to the vendor ID list. */ diff --git a/trunk/drivers/media/video/cx23885/cx23885-417.c b/trunk/drivers/media/video/cx23885/cx23885-417.c index 53a67824071b..abd64e89f60f 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-417.c +++ b/trunk/drivers/media/video/cx23885/cx23885-417.c @@ -7,7 +7,7 @@ * (c) 2008 Steven Toth * - CX23885/7/8 support * - * Includes parts from the ivtv driver + * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), * * 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 diff --git a/trunk/drivers/media/video/cx88/cx88-blackbird.c b/trunk/drivers/media/video/cx88/cx88-blackbird.c index 660b2a927feb..e46e1ceef72c 100644 --- a/trunk/drivers/media/video/cx88/cx88-blackbird.c +++ b/trunk/drivers/media/video/cx88/cx88-blackbird.c @@ -9,7 +9,7 @@ * (c) 2005-2006 Mauro Carvalho Chehab * - video_ioctl2 conversion * - * Includes parts from the ivtv driver + * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), * * 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 diff --git a/trunk/drivers/media/video/ivtv/ivtv-cards.c b/trunk/drivers/media/video/ivtv/ivtv-cards.c index 87afbbee2063..ca1fd3227a93 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-cards.c +++ b/trunk/drivers/media/video/ivtv/ivtv-cards.c @@ -65,7 +65,7 @@ static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { /********************** card configuration *******************************/ -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii This keeps the PCI ID database up to date. Note that the entries must be added under vendor 0x4444 (Conexant) as subsystem IDs. New vendor IDs should still be added to the vendor ID list. */ diff --git a/trunk/drivers/media/video/mxb.c b/trunk/drivers/media/video/mxb.c index b1dbcf1d2bcb..ef0c8178f255 100644 --- a/trunk/drivers/media/video/mxb.c +++ b/trunk/drivers/media/video/mxb.c @@ -3,7 +3,7 @@ Copyright (C) 1998-2006 Michael Hunold - Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html + Visit http://www.mihu.de/linux/saa7146/mxb/ for further details about this card. This program is free software; you can redistribute it and/or modify diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index 2e86fdc86989..2782f94cf6f8 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c @@ -4,6 +4,7 @@ * * * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * * * + * http://cadu.homelinux.com:8080/ * * * * Support for SN9C103, DAC Magnitude, exposure and green gain controls * * added by Luca Risolia * diff --git a/trunk/drivers/media/video/zoran/videocodec.h b/trunk/drivers/media/video/zoran/videocodec.h index b654bfff8740..5c27b251354e 100644 --- a/trunk/drivers/media/video/zoran/videocodec.h +++ b/trunk/drivers/media/video/zoran/videocodec.h @@ -56,7 +56,7 @@ the slave is bound to it). Otherwise it doesn't need this functions and therfor they may not be initialized. - The other functions are just for convenience, as they are for sure used by + The other fuctions are just for convenience, as they are for sure used by most/all of the codecs. The last ones may be ommited, too. See the structure declaration below for more information and which data has diff --git a/trunk/drivers/media/video/zoran/zoran_driver.c b/trunk/drivers/media/video/zoran/zoran_driver.c index 3c471a4e3e4a..6f89d0a096ea 100644 --- a/trunk/drivers/media/video/zoran/zoran_driver.c +++ b/trunk/drivers/media/video/zoran/zoran_driver.c @@ -1177,7 +1177,7 @@ static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height if (height > BUZ_MAX_HEIGHT) height = BUZ_MAX_HEIGHT; - /* Check for invalid parameters */ + /* Check for vaild parameters */ if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT || width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) { dprintk(1, diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 1f69743b12ec..db2fbe2d4146 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -112,8 +112,8 @@ config IBM_ASM WARNING: This software may not be supported or function correctly on your IBM server. Please consult the IBM ServerProven - website - for information on the specific driver level and support statement + website for + information on the specific driver level and support statement for your IBM server. config PHANTOM @@ -385,7 +385,7 @@ config BMP085 depends on I2C && SYSFS help If you say yes here you get support for the Bosch Sensortec - BMP085 digital pressure sensor. + BMP086 digital pressure sensor. To compile this driver as a module, choose M here: the module will be called bmp085. diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c index ba29d2f0ffd7..3e6c47bdce53 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c @@ -418,8 +418,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) /* * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4 - * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19 - * http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf + * see: http://www.amd.com/us-en/assets/content_type/DownloadableAssets/cfi_r20.pdf, page 19 + * http://www.amd.com/us-en/assets/content_type/DownloadableAssets/cfi_100_20011201.pdf * http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf */ if (extp->MajorVersion != '1' || diff --git a/trunk/drivers/mtd/devices/lart.c b/trunk/drivers/mtd/devices/lart.c index caf604167f03..f4359fe7150f 100644 --- a/trunk/drivers/mtd/devices/lart.c +++ b/trunk/drivers/mtd/devices/lart.c @@ -17,7 +17,7 @@ * - January 2000 * * [2] MTD internal API documentation - * - http://www.linux-mtd.infradead.org/ + * - http://www.linux-mtd.infradead.org/tech/ * * Limitations: * diff --git a/trunk/drivers/mtd/ftl.c b/trunk/drivers/mtd/ftl.c index 037b399df3f1..4d6a64c387ec 100644 --- a/trunk/drivers/mtd/ftl.c +++ b/trunk/drivers/mtd/ftl.c @@ -51,7 +51,7 @@ Use of the FTL format for non-PCMCIA applications may be an infringement of these patents. For additional information, - contact M-Systems directly. M-Systems since acquired by Sandisk. + contact M-Systems (http://www.m-sys.com) directly. ======================================================================*/ #include diff --git a/trunk/drivers/mtd/maps/Kconfig b/trunk/drivers/mtd/maps/Kconfig index 962212628f6e..701d942c6795 100644 --- a/trunk/drivers/mtd/maps/Kconfig +++ b/trunk/drivers/mtd/maps/Kconfig @@ -172,7 +172,7 @@ config MTD_OCTAGON This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Octagon-5066 Single Board Computer. More information on the board is available at - . + . config MTD_VMAX tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301" @@ -284,7 +284,7 @@ config MTD_TQM8XXL chips, currently uses AMD one. This 'mapping' driver supports that arrangement, allowing the CFI probe and command set driver code to communicate with the chips on the TQM8xxL board. More at - . + . config MTD_RPXLITE tristate "CFI Flash device mapped on RPX Lite or CLLF" diff --git a/trunk/drivers/mtd/nand/cafe_nand.c b/trunk/drivers/mtd/nand/cafe_nand.c index e06c8983978e..db1dfc5a1b11 100644 --- a/trunk/drivers/mtd/nand/cafe_nand.c +++ b/trunk/drivers/mtd/nand/cafe_nand.c @@ -2,7 +2,7 @@ * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01 * * The data sheet for this device can be found at: - * http://wiki.laptop.org/go/Datasheets + * http://www.marvell.com/products/pcconn/88ALP01.jsp * * Copyright © 2006 Red Hat, Inc. * Copyright © 2006 David Woodhouse diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 77c1fab7d774..7ca1fc8a3a76 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -924,7 +924,7 @@ config SMC91X including the SMC91C94 and the SMC91C111. Say Y if you want it compiled into the kernel, and read the file and the Ethernet-HOWTO, - available from . + available from . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -1034,7 +1034,7 @@ config SMC911X including the new LAN9115, LAN9116, LAN9117, and LAN9118. Say Y if you want it compiled into the kernel, and read the Ethernet-HOWTO, available from - . + . This driver is also available as a module. The module will be called smc911x. If you want to compile it as a module, say M @@ -1516,7 +1516,7 @@ config E100 For the latest Intel PRO/100 network driver for Linux, see: - + More specific information on configuring the driver is in . @@ -1542,8 +1542,9 @@ config FEALNX select CRC32 select MII help - Say Y here to support the Myson MTD-800 family of PCI-based Ethernet - cards. + Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet + cards. Specifications and data at + . config NATSEMI tristate "National Semiconductor DP8381x series PCI Ethernet support" @@ -1717,7 +1718,7 @@ config SMSC9420 This is a driver for SMSC's LAN9420 PCI ethernet adapter. Say Y if you want it compiled into the kernel, and read the Ethernet-HOWTO, available from - . + . This driver is also available as a module. The module will be called smsc9420. If you want to compile it as a module, say M @@ -2564,7 +2565,7 @@ config CHELSIO_T1 our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . @@ -2596,7 +2597,7 @@ config CHELSIO_T3 our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . @@ -2621,7 +2622,7 @@ config CHELSIO_T4 our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . @@ -2644,7 +2645,7 @@ config CHELSIO_T4VF our website at . For customer support, please visit our customer support page at - . + . Please send feedback to . diff --git a/trunk/drivers/net/appletalk/Kconfig b/trunk/drivers/net/appletalk/Kconfig index 0b376a990972..20f97e7017ce 100644 --- a/trunk/drivers/net/appletalk/Kconfig +++ b/trunk/drivers/net/appletalk/Kconfig @@ -19,7 +19,7 @@ config ATALK General information about how to connect Linux, Windows machines and Macs is on the WWW at . The - NET3-4-HOWTO, available from + NET-3-HOWTO, available from , contains valuable information as well. diff --git a/trunk/drivers/net/atp.c b/trunk/drivers/net/atp.c index f3459798b0e9..dfd96b20547f 100644 --- a/trunk/drivers/net/atp.c +++ b/trunk/drivers/net/atp.c @@ -68,7 +68,7 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */ In 1997 Realtek made available the documentation for the second generation RTL8012 chip, which has lead to several driver improvements. - http://www.realtek.com.tw/ + http://www.realtek.com.tw/cn/cn.html Theory of Operation diff --git a/trunk/drivers/net/depca.c b/trunk/drivers/net/depca.c index 91b3846ffc8a..44c0694c1f4e 100644 --- a/trunk/drivers/net/depca.c +++ b/trunk/drivers/net/depca.c @@ -1487,7 +1487,7 @@ static void __init depca_platform_probe (void) if (!pldev->dev.driver) { /* The driver was not bound to this device, there was * no hardware at this address. Unregister it, as the - * release function will take care of freeing the + * release fuction will take care of freeing the * allocated structure */ depca_io_ports[i].device = NULL; diff --git a/trunk/drivers/net/epic100.c b/trunk/drivers/net/epic100.c index aa56963ad558..32543a300b81 100644 --- a/trunk/drivers/net/epic100.c +++ b/trunk/drivers/net/epic100.c @@ -131,8 +131,8 @@ IIIa. Ring buffers IVb. References -http://www.smsc.com/media/Downloads_Public/discontinued/83c171.pdf -http://www.smsc.com/media/Downloads_Public/discontinued/83c175.pdf +http://www.smsc.com/main/tools/discontinued/83c171.pdf +http://www.smsc.com/main/tools/discontinued/83c175.pdf http://scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html diff --git a/trunk/drivers/net/hamradio/Kconfig b/trunk/drivers/net/hamradio/Kconfig index 95dbcfdf131d..62d5d5cfd6a6 100644 --- a/trunk/drivers/net/hamradio/Kconfig +++ b/trunk/drivers/net/hamradio/Kconfig @@ -73,7 +73,7 @@ config DMASCC certain parameters, such as channel access timing, clock mode, and DMA channel. This is accomplished with a small utility program, dmascc_cfg, available at - . Please be sure to + . Please be sure to get at least version 1.27 of dmascc_cfg, as older versions will not work with the current driver. diff --git a/trunk/drivers/net/ibmlana.c b/trunk/drivers/net/ibmlana.c index 94d9969ec0bb..0037a696cd0a 100644 --- a/trunk/drivers/net/ibmlana.c +++ b/trunk/drivers/net/ibmlana.c @@ -23,7 +23,7 @@ paper sources: 'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0 Document Number SC30-3661-00' by IBM for info on the adapter itself - Also see http://www.national.com/analog + Also see http://www.natsemi.com/ special acknowledgements to: - Bob Eager for helping me out with documentation from IBM diff --git a/trunk/drivers/net/igb/igb_main.c b/trunk/drivers/net/igb/igb_main.c index 14db09e2fa8b..75155a27fdde 100644 --- a/trunk/drivers/net/igb/igb_main.c +++ b/trunk/drivers/net/igb/igb_main.c @@ -3540,7 +3540,7 @@ enum latency_range { * Stores a new ITR value based on strictly on packet size. This * algorithm is less sophisticated than that used in igb_update_itr, * due to the difficulty of synchronizing statistics across multiple - * receive rings. The divisors and thresholds used by this function + * receive rings. The divisors and thresholds used by this fuction * were determined based on theoretical maximum wire speed and testing * data, in order to minimize response time while increasing bulk * throughput. diff --git a/trunk/drivers/net/irda/ali-ircc.c b/trunk/drivers/net/irda/ali-ircc.c index 92631eb6f6a3..a3cb109006a5 100644 --- a/trunk/drivers/net/irda/ali-ircc.c +++ b/trunk/drivers/net/irda/ali-ircc.c @@ -142,7 +142,7 @@ static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable); * Function ali_ircc_init () * * Initialize chip. Find out whay kinds of chips we are dealing with - * and their configuration registers address + * and their configuation registers address */ static int __init ali_ircc_init(void) { diff --git a/trunk/drivers/net/irda/donauboe.h b/trunk/drivers/net/irda/donauboe.h index 4dc39e5f0156..36c3060411d2 100644 --- a/trunk/drivers/net/irda/donauboe.h +++ b/trunk/drivers/net/irda/donauboe.h @@ -54,7 +54,7 @@ /* anyone who has. HOWEVER the chip bears a striking resemblence */ /* to the IrDA controller in the Toshiba RISC TMPR3922 chip */ /* the documentation for this is freely available at */ -/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */ +/* http://www.toshiba.com/taec/components/Generic/TMPR3922.shtml */ /* The mapping between the registers in that document and the */ /* Registers in the 701 oboe chip are as follows */ diff --git a/trunk/drivers/net/pci-skeleton.c b/trunk/drivers/net/pci-skeleton.c index 1766dc4f07e1..8dd03439d994 100644 --- a/trunk/drivers/net/pci-skeleton.c +++ b/trunk/drivers/net/pci-skeleton.c @@ -78,7 +78,7 @@ that almost all frames will need to be copied to an alignment buffer. IVb. References -http://www.realtek.com.tw/ +http://www.realtek.com.tw/cn/cn.html http://www.scyld.com/expert/NWay.html IVc. Errata diff --git a/trunk/drivers/net/pcmcia/3c574_cs.c b/trunk/drivers/net/pcmcia/3c574_cs.c index 321b12f82645..2807a0fcadc4 100644 --- a/trunk/drivers/net/pcmcia/3c574_cs.c +++ b/trunk/drivers/net/pcmcia/3c574_cs.c @@ -62,7 +62,7 @@ invalid ramWidth is Very Bad. V. References http://www.scyld.com/expert/NWay.html -http://www.national.com/opf/DP/DP83840A.html +http://www.national.com/pf/DP/DP83840.html Thanks to Terry Murphy of 3Com for providing development information for earlier 3Com products. diff --git a/trunk/drivers/net/ps3_gelic_net.c b/trunk/drivers/net/ps3_gelic_net.c index 5ecfa4b1e758..5526ab4895e6 100644 --- a/trunk/drivers/net/ps3_gelic_net.c +++ b/trunk/drivers/net/ps3_gelic_net.c @@ -642,7 +642,7 @@ static inline void gelic_card_disable_rxdmac(struct gelic_card *card) status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0); if (status) dev_err(ctodev(card), - "lv1_net_stop_rx_dma failed, %d\n", status); + "lv1_net_stop_rx_dma faild, %d\n", status); } /** @@ -660,7 +660,7 @@ static inline void gelic_card_disable_txdmac(struct gelic_card *card) status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0); if (status) dev_err(ctodev(card), - "lv1_net_stop_tx_dma failed, status=%d\n", status); + "lv1_net_stop_tx_dma faild, status=%d\n", status); } /** diff --git a/trunk/drivers/net/sb1250-mac.c b/trunk/drivers/net/sb1250-mac.c index d96d2f7a3f14..d8249d7653c6 100644 --- a/trunk/drivers/net/sb1250-mac.c +++ b/trunk/drivers/net/sb1250-mac.c @@ -95,7 +95,7 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #include #include #else -#error invalid SiByte MAC configuration +#error invalid SiByte MAC configuation #endif #include #include @@ -106,7 +106,7 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #define UNIT_INT(n) (K_INT_MAC_0 + (n)) #else -#error invalid SiByte MAC configuration +#error invalid SiByte MAC configuation #endif #ifdef K_INT_PHY @@ -1568,7 +1568,7 @@ static void sbmac_channel_start(struct sbmac_softc *s) M_MAC_RX_ENABLE | M_MAC_TX_ENABLE, s->sbm_macenable); #else -#error invalid SiByte MAC configuration +#error invalid SiByte MAC configuation #endif #ifdef CONFIG_SBMAC_COALESCE diff --git a/trunk/drivers/net/sc92031.c b/trunk/drivers/net/sc92031.c index 417adf372828..31b92f5f32cb 100644 --- a/trunk/drivers/net/sc92031.c +++ b/trunk/drivers/net/sc92031.c @@ -15,7 +15,7 @@ * Rewritten for 2.6 by Cesar Eduardo Barros * * A datasheet for this chip can be found at - * http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf + * http://www.silan.com.cn/english/products/pdf/SC92031AY.pdf */ /* Note about set_mac_address: I don't know how to change the hardware diff --git a/trunk/drivers/net/skfp/hwt.c b/trunk/drivers/net/skfp/hwt.c index c0798fd2ca69..e6baa53307c7 100644 --- a/trunk/drivers/net/skfp/hwt.c +++ b/trunk/drivers/net/skfp/hwt.c @@ -221,7 +221,7 @@ u_long hwt_quick_read(struct s_smc *smc) * para start start time * duration time to wait * - * NOTE: The function will return immediately, if the timer is not + * NOTE: The fuction will return immediately, if the timer is not * started ************************/ void hwt_wait_time(struct s_smc *smc, u_long start, long int duration) diff --git a/trunk/drivers/net/skfp/skfddi.c b/trunk/drivers/net/skfp/skfddi.c index 0a66fed52e8e..ba2e8339fe90 100644 --- a/trunk/drivers/net/skfp/skfddi.c +++ b/trunk/drivers/net/skfp/skfddi.c @@ -33,7 +33,7 @@ * The driver architecture is based on the DEC FDDI driver by * Lawrence V. Stefani and several ethernet drivers. * I also used an existing Windows NT miniport driver. - * All hardware dependent functions are handled by the SysKonnect + * All hardware dependent fuctions are handled by the SysKonnect * Hardware Module. * The only headerfiles that are directly related to this source * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. diff --git a/trunk/drivers/net/tlan.c b/trunk/drivers/net/tlan.c index f8e463cd8ecc..ec8c804a795d 100644 --- a/trunk/drivers/net/tlan.c +++ b/trunk/drivers/net/tlan.c @@ -78,7 +78,7 @@ * - Updated tlan.txt accordingly. * - Adjusted minimum/maximum frame length. * - There is now a TLAN website up at - * http://hp.sourceforge.net/ + * http://tlan.kernel.dk * * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now * reports PHY information when used with Donald diff --git a/trunk/drivers/net/tokenring/tms380tr.c b/trunk/drivers/net/tokenring/tms380tr.c index 663b8860a531..c83f4f6e39e1 100644 --- a/trunk/drivers/net/tokenring/tms380tr.c +++ b/trunk/drivers/net/tokenring/tms380tr.c @@ -5,7 +5,7 @@ * Originally sktr.c: Written 1997 by Christoph Goos * * A fine result of the Linux Systems Network Architecture Project. - * http://www.vanheusden.com/sna/ + * http://www.linux-sna.org * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. diff --git a/trunk/drivers/net/tulip/Kconfig b/trunk/drivers/net/tulip/Kconfig index 1f8d4a8d8ea4..f3035951422f 100644 --- a/trunk/drivers/net/tulip/Kconfig +++ b/trunk/drivers/net/tulip/Kconfig @@ -151,7 +151,7 @@ config ULI526X select CRC32 ---help--- This driver is for ULi M5261/M5263 10/100M Ethernet Controller - (). + (). To compile this driver as a module, choose M here. The module will be called uli526x. diff --git a/trunk/drivers/net/tulip/pnic2.c b/trunk/drivers/net/tulip/pnic2.c index 4690c8e69207..b8197666021e 100644 --- a/trunk/drivers/net/tulip/pnic2.c +++ b/trunk/drivers/net/tulip/pnic2.c @@ -59,7 +59,7 @@ * Bit 14:12 - autonegotiation state (write 001 to start autonegotiate) * Bit 3 - Autopolarity state * Bit 2 - LS10B - link state of 10baseT 0 - good, 1 - failed - * Bit 1 - LS100B - link state of 100baseT 0 - good, 1 - failed + * Bit 1 - LS100B - link state of 100baseT 0 - good, 1- faild * * * Data Port Selection Info diff --git a/trunk/drivers/net/usb/plusb.c b/trunk/drivers/net/usb/plusb.c index 08ad269f6b4e..08555f8b15f4 100644 --- a/trunk/drivers/net/usb/plusb.c +++ b/trunk/drivers/net/usb/plusb.c @@ -32,7 +32,7 @@ /* - * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/ + * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com * * The protocol and handshaking used here should be bug-compatible * with the Linux 2.2 "plusb" driver, by Deti Fliegl. diff --git a/trunk/drivers/net/wan/Kconfig b/trunk/drivers/net/wan/Kconfig index 423eb26386c8..d08ce6a264cb 100644 --- a/trunk/drivers/net/wan/Kconfig +++ b/trunk/drivers/net/wan/Kconfig @@ -409,7 +409,7 @@ config CYCLADES_SYNC tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" depends on WAN_ROUTER_DRIVERS && (PCI || ISA) ---help--- - Cyclom 2X from Cyclades Corporation is an + Cyclom 2X from Cyclades Corporation is an intelligent multiprotocol WAN adapter with data transfer rates up to 512 Kbps. These cards support the X.25 and SNA related protocols. diff --git a/trunk/drivers/net/wan/hdlc.c b/trunk/drivers/net/wan/hdlc.c index 5d4bb615ccce..9937bbab938d 100644 --- a/trunk/drivers/net/wan/hdlc.c +++ b/trunk/drivers/net/wan/hdlc.c @@ -109,7 +109,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, return NOTIFY_DONE; /* not an HDLC device */ if (event != NETDEV_CHANGE) - return NOTIFY_DONE; /* Only interested in carrier changes */ + return NOTIFY_DONE; /* Only interrested in carrier changes */ on = netif_carrier_ok(dev); diff --git a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h index 308b79e1ff08..4a367cdb3eb9 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h @@ -348,7 +348,7 @@ struct ath5k_srev_name { /* * Some of this information is based on Documentation from: * - * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG + * http://madwifi.org/wiki/ChipsetFeatures/SuperAG * * Modulation for Atheros' eXtended Range - range enhancing extension that is * supposed to double the distance an Atheros client device can keep a diff --git a/trunk/drivers/net/wireless/ath/ath5k/reg.h b/trunk/drivers/net/wireless/ath/ath5k/reg.h index ca79ecd832fd..a34929f06533 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/reg.h +++ b/trunk/drivers/net/wireless/ath/ath5k/reg.h @@ -26,6 +26,7 @@ * Atheros presentations and papers like these: * * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf + * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf * * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf * diff --git a/trunk/drivers/net/wireless/hostap/hostap_hw.c b/trunk/drivers/net/wireless/hostap/hostap_hw.c index b7cb165d612b..e9d9d622a9b0 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_hw.c +++ b/trunk/drivers/net/wireless/hostap/hostap_hw.c @@ -2621,7 +2621,7 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) iface = netdev_priv(dev); local = iface->local; - /* Detect early interrupt before driver is fully configured */ + /* Detect early interrupt before driver is fully configued */ spin_lock(&local->irq_init_lock); if (!dev->base_addr) { if (net_ratelimit()) { diff --git a/trunk/drivers/net/wireless/p54/Kconfig b/trunk/drivers/net/wireless/p54/Kconfig index 25f965ffc889..e5f45cb2a7a2 100644 --- a/trunk/drivers/net/wireless/p54/Kconfig +++ b/trunk/drivers/net/wireless/p54/Kconfig @@ -9,7 +9,7 @@ config P54_COMMON also need to be enabled in order to support any devices. These devices require softmac firmware which can be found at - + http://prism54.org/ If you choose to build a module, it'll be called p54common. @@ -21,7 +21,7 @@ config P54_USB This driver is for USB isl38xx based wireless cards. These devices require softmac firmware which can be found at - + http://prism54.org/ If you choose to build a module, it'll be called p54usb. @@ -35,7 +35,7 @@ config P54_PCI supported by the fullmac driver/firmware. This driver requires softmac firmware which can be found at - + http://prism54.org/ If you choose to build a module, it'll be called p54pci. diff --git a/trunk/drivers/net/wireless/prism54/islpci_hotplug.c b/trunk/drivers/net/wireless/prism54/islpci_hotplug.c index b5e64d71b7a6..dc14420a9adc 100644 --- a/trunk/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/trunk/drivers/net/wireless/prism54/islpci_hotplug.c @@ -38,7 +38,7 @@ module_param(init_pcitm, int, 0); /* In this order: vendor, device, subvendor, subdevice, class, class_mask, * driver_data * If you have an update for this please contact prism54-devel@prism54.org - * The latest list can be found at http://wireless.kernel.org/en/users/Drivers/p54 */ + * The latest list can be found at http://prism54.org/supported_cards.php */ static DEFINE_PCI_DEVICE_TABLE(prism54_id_tbl) = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ { diff --git a/trunk/drivers/parisc/README.dino b/trunk/drivers/parisc/README.dino index 1627426996c1..097324f34bbe 100644 --- a/trunk/drivers/parisc/README.dino +++ b/trunk/drivers/parisc/README.dino @@ -10,7 +10,8 @@ ** PCI bus. HP-supplied graphics cards that utilize the PCI bus are ** not affected." ** -** http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?locale=en_US&prodTypeId=12454&prodSeriesId=44443 +** REVISIT: "go/pci_defect" link below is stale. +** HP Internal can use ** ** Product First Good Serial Number ** C200/C240 (US) US67350000 diff --git a/trunk/drivers/parport/parport_pc.c b/trunk/drivers/parport/parport_pc.c index 8d62fb76cd41..0950fa40684f 100644 --- a/trunk/drivers/parport/parport_pc.c +++ b/trunk/drivers/parport/parport_pc.c @@ -2599,7 +2599,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n"); return 0; case 0x8: - printk(KERN_INFO "parport_pc: ITE8874 found (2S)\n"); + DPRINTK(KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); return 0; default: printk(KERN_INFO "parport_pc: unknown ITE887x\n"); diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index cc96c7142dac..857ae01734a6 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -226,7 +226,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir * VIA Apollo KT133 needs PCI latency patch * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm - * and http://www.georgebreese.com/net/software/#PCI * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for * the info on which Mr Breese based his work. * @@ -1017,7 +1016,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge) /* * Common misconfiguration of the MediaGX/Geode PCI master that will * reduce PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1 - * datasheets found at http://www.national.com/analog for info on what + * datasheets found at http://www.national.com/ds/GX for info on what * these bits do. */ static void quirk_mediagx_master(struct pci_dev *dev) diff --git a/trunk/drivers/pcmcia/yenta_socket.c b/trunk/drivers/pcmcia/yenta_socket.c index 9dc565c615bd..408dbaa080a1 100644 --- a/trunk/drivers/pcmcia/yenta_socket.c +++ b/trunk/drivers/pcmcia/yenta_socket.c @@ -1072,7 +1072,7 @@ static void yenta_config_init(struct yenta_socket *socket) * invisible during PCI scans because of a misconfigured subordinate number * of the parent brige - some BIOSes seem to be too lazy to set it right. * Does the fixup carefully by checking how far it can go without conflicts. - * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information. + * See http\://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information. */ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge) { diff --git a/trunk/drivers/pnp/pnpbios/proc.c b/trunk/drivers/pnp/pnpbios/proc.c index bc89f392a629..2d8ac43f78e8 100644 --- a/trunk/drivers/pnp/pnpbios/proc.c +++ b/trunk/drivers/pnp/pnpbios/proc.c @@ -11,6 +11,7 @@ * * The .../escd file is utilized by the lsescd utility written by * Gunther Mayer. + * http://home.t-online.de/home/gunther.mayer/lsescd * * The .../legacy_device_resources file is not used yet. * diff --git a/trunk/drivers/rtc/rtc-nuc900.c b/trunk/drivers/rtc/rtc-nuc900.c index ddb0857e15a4..62de66af0a68 100644 --- a/trunk/drivers/rtc/rtc-nuc900.c +++ b/trunk/drivers/rtc/rtc-nuc900.c @@ -274,7 +274,7 @@ static int __devinit nuc900_rtc_probe(struct platform_device *pdev) nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, &nuc900_rtc_ops, THIS_MODULE); if (IS_ERR(nuc900_rtc->rtcdev)) { - dev_err(&pdev->dev, "rtc device register failed\n"); + dev_err(&pdev->dev, "rtc device register faild\n"); err = PTR_ERR(nuc900_rtc->rtcdev); goto fail3; } diff --git a/trunk/drivers/s390/block/dasd_3990_erp.c b/trunk/drivers/s390/block/dasd_3990_erp.c index e82d427ff5eb..85bfd8794856 100644 --- a/trunk/drivers/s390/block/dasd_3990_erp.c +++ b/trunk/drivers/s390/block/dasd_3990_erp.c @@ -2197,7 +2197,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) /* ***************************************************************************** - * main ERP control functions (24 and 32 byte sense) + * main ERP control fuctions (24 and 32 byte sense) ***************************************************************************** */ diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index 59b4ecfb967b..66360c24bd48 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -1190,7 +1190,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) goto out_err2; } /* - * dasd_eckd_validate_server is done on the first device that + * dasd_eckd_vaildate_server is done on the first device that * is found for an LCU. All later other devices have to wait * for it, so they will read the correct feature codes. */ @@ -1216,7 +1216,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) "Read device characteristic failed, rc=%d", rc); goto out_err3; } - /* find the valid cylinder size */ + /* find the vaild cylinder size */ if (private->rdc_data.no_cyl == LV_COMPAT_CYL && private->rdc_data.long_no_cyl) private->real_cyl = private->rdc_data.long_no_cyl; diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c index deff2c3361e4..fc993acf99b6 100644 --- a/trunk/drivers/s390/char/tape_3590.c +++ b/trunk/drivers/s390/char/tape_3590.c @@ -31,7 +31,7 @@ debug_info_t *TAPE_DBF_AREA = NULL; EXPORT_SYMBOL(TAPE_DBF_AREA); /******************************************************************* - * Error Recovery functions: + * Error Recovery fuctions: * - Read Opposite: implemented * - Read Device (buffered) log: BRA * - Read Library log: BRA @@ -798,7 +798,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) } /* - * This function is called, when error recovery was successful + * This fuction is called, when error recovery was successfull */ static inline int tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) @@ -809,7 +809,7 @@ tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) } /* - * This function is called, when error recovery was not successful + * This fuction is called, when error recovery was not successfull */ static inline int tape_3590_erp_failed(struct tape_device *device, struct tape_request *request, diff --git a/trunk/drivers/s390/char/vmcp.c b/trunk/drivers/s390/char/vmcp.c index 31a3ccbb6495..0e7cb1a84151 100644 --- a/trunk/drivers/s390/char/vmcp.c +++ b/trunk/drivers/s390/char/vmcp.c @@ -47,7 +47,7 @@ static int vmcp_release(struct inode *inode, struct file *file) { struct vmcp_session *session; - session = file->private_data; + session = (struct vmcp_session *)file->private_data; file->private_data = NULL; free_pages((unsigned long)session->response, get_order(session->bufsize)); kfree(session); @@ -94,7 +94,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, return -EFAULT; } cmd[count] = '\0'; - session = file->private_data; + session = (struct vmcp_session *)file->private_data; if (mutex_lock_interruptible(&session->mutex)) { kfree(cmd); return -ERESTARTSYS; @@ -136,7 +136,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int __user *argp; int temp; - session = file->private_data; + session = (struct vmcp_session *)file->private_data; if (is_compat_task()) argp = compat_ptr(arg); else diff --git a/trunk/drivers/s390/kvm/kvm_virtio.c b/trunk/drivers/s390/kvm/kvm_virtio.c index 5a46b8c5d68a..4e298bc8949d 100644 --- a/trunk/drivers/s390/kvm/kvm_virtio.c +++ b/trunk/drivers/s390/kvm/kvm_virtio.c @@ -32,7 +32,6 @@ * The pointer to our (page) of device descriptions. */ static void *kvm_devices; -struct work_struct hotplug_work; struct kvm_device { struct virtio_device vdev; @@ -328,47 +327,6 @@ static void scan_devices(void) } } -/* - * match for a kvm device with a specific desc pointer - */ -static int match_desc(struct device *dev, void *data) -{ - if ((ulong)to_kvmdev(dev_to_virtio(dev))->desc == (ulong)data) - return 1; - - return 0; -} - -/* - * hotplug_device tries to find changes in the device page. - */ -static void hotplug_devices(struct work_struct *dummy) -{ - unsigned int i; - struct kvm_device_desc *d; - struct device *dev; - - for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { - d = kvm_devices + i; - - /* end of list */ - if (d->type == 0) - break; - - /* device already exists */ - dev = device_find_child(kvm_root, d, match_desc); - if (dev) { - /* XXX check for hotplug remove */ - put_device(dev); - continue; - } - - /* new device */ - printk(KERN_INFO "Adding new virtio device %p\n", d); - add_kvm_device(d, i); - } -} - /* * we emulate the request_irq behaviour on top of s390 extints */ @@ -376,7 +334,7 @@ static void kvm_extint_handler(u16 code) { struct virtqueue *vq; u16 subcode; - u32 param; + int config_changed; subcode = S390_lowcore.cpu_addr; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) @@ -385,28 +343,18 @@ static void kvm_extint_handler(u16 code) /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL); - /* We use ext_params to decide what this interrupt means */ - param = S390_lowcore.ext_params & VIRTIO_PARAM_MASK; + /* We use the LSB of extparam, to decide, if this interrupt is a config + * change or a "standard" interrupt */ + config_changed = S390_lowcore.ext_params & 1; - switch (param) { - case VIRTIO_PARAM_CONFIG_CHANGED: - { + if (config_changed) { struct virtio_driver *drv; drv = container_of(vq->vdev->dev.driver, struct virtio_driver, driver); if (drv->config_changed) drv->config_changed(vq->vdev); - - break; - } - case VIRTIO_PARAM_DEV_ADD: - schedule_work(&hotplug_work); - break; - case VIRTIO_PARAM_VRING_INTERRUPT: - default: + } else vring_interrupt(0, vq); - break; - } } /* @@ -435,8 +383,6 @@ static int __init kvm_devices_init(void) kvm_devices = (void *) real_memory_size; - INIT_WORK(&hotplug_work, hotplug_devices); - ctl_set_bit(0, 9); register_external_interrupt(0x2603, kvm_extint_handler); diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index 8616496ffc02..2e9632e2c98b 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -116,7 +116,7 @@ config CHR_DEV_OSST and in the kernel source. More info on the OnStream driver may be found on - + Please also have a look at the standard st docu, as most of it applies to osst as well. @@ -156,9 +156,9 @@ config CHR_DEV_SG directly, so you need some additional software which knows how to talk to these devices using the SCSI protocol: - For scanners, look at SANE (). For CD + For scanners, look at SANE (). For CD writer software look at Cdrtools - () + () and for burning a "disk at once": CDRDAO (). Cdparanoia is a high quality digital reader of audio CDs (). @@ -951,7 +951,6 @@ config SCSI_IPS ---help--- This is support for the IBM ServeRAID hardware RAID controllers. See - and for more information. If this driver does not work correctly without modification please contact the author by email at . @@ -1611,7 +1610,7 @@ config SCSI_DEBUG host adapter with one dummy SCSI disk. Each dummy disk uses kernel RAM as storage (i.e. it is a ramdisk). To save space when multiple dummy disks are simulated, they share the same kernel RAM for - their storage. See for more + their storage. See for more information. This driver is primarily of use to those testing the SCSI and block subsystems. If unsure, say N. diff --git a/trunk/drivers/scsi/aacraid/linit.c b/trunk/drivers/scsi/aacraid/linit.c index 29c0ed1cf507..dae46d779c7b 100644 --- a/trunk/drivers/scsi/aacraid/linit.c +++ b/trunk/drivers/scsi/aacraid/linit.c @@ -771,7 +771,7 @@ static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long { if (!capable(CAP_SYS_RAWIO)) return -EPERM; - return aac_compat_do_ioctl(file->private_data, cmd, arg); + return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg); } #endif diff --git a/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c b/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c index a345dde16c86..c3d7174e3469 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5509,7 +5509,7 @@ lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type) * @buff: Buffer containing config region 23 data. * @size: Size of the data buffer. * - * This function parses the FCoE config parameters in config region 23 and + * This fuction parse the FCoE config parameters in config region 23 and * populate driver data structure with the parameters. */ void diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index 909ed9ed24c0..5428d53f5a13 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -212,7 +212,7 @@ static void sg_put_dev(Sg_device *sdp); static int sg_allow_access(struct file *filp, unsigned char *cmd) { - struct sg_fd *sfp = filp->private_data; + struct sg_fd *sfp = (struct sg_fd *)filp->private_data; if (sfp->parentdp->device->type == TYPE_SCANNER) return 0; diff --git a/trunk/drivers/serial/68328serial.h b/trunk/drivers/serial/68328serial.h index 664ceb0a158c..58aa2154655b 100644 --- a/trunk/drivers/serial/68328serial.h +++ b/trunk/drivers/serial/68328serial.h @@ -181,8 +181,13 @@ struct m68k_serial { /* * Define the number of ports supported and their irqs. */ +#ifndef CONFIG_68328_SERIAL_UART2 #define NR_PORTS 1 #define UART_IRQ_DEFNS {UART_IRQ_NUM} +#else +#define NR_PORTS 2 +#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM} +#endif #endif /* __KERNEL__ */ #endif /* !(_MC683XX_SERIAL_H) */ diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index 4d8e14b7aa93..167c4a6ccbc3 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -919,7 +919,7 @@ static int broken_efr(struct uart_8250_port *up) /* * Exar ST16C2550 "A2" devices incorrectly detect as * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + * http://www.exar.com/info.php?pdf=dan180_oct2004.pdf */ if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) return 1; diff --git a/trunk/drivers/serial/bfin_sport_uart.c b/trunk/drivers/serial/bfin_sport_uart.c index e95c524d9d18..6f1b51e231e4 100644 --- a/trunk/drivers/serial/bfin_sport_uart.c +++ b/trunk/drivers/serial/bfin_sport_uart.c @@ -10,7 +10,7 @@ /* * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/static/imported-files/application_notes/EE191.pdf + * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf * This application note describe how to implement a UART on a Sharc DSP, * but this driver is implemented on Blackfin Processor. * Transmit Frame Sync is not used by this driver to transfer data out. diff --git a/trunk/drivers/serial/bfin_sport_uart.h b/trunk/drivers/serial/bfin_sport_uart.h index 6d06ce1d5675..9ce253e381d2 100644 --- a/trunk/drivers/serial/bfin_sport_uart.h +++ b/trunk/drivers/serial/bfin_sport_uart.h @@ -10,7 +10,7 @@ /* * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/static/imported-files/application_notes/EE191.pdf + * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf * This application note describe how to implement a UART on a Sharc DSP, * but this driver is implemented on Blackfin Processor. * Transmit Frame Sync is not used by this driver to transfer data out. diff --git a/trunk/drivers/serial/uartlite.c b/trunk/drivers/serial/uartlite.c index d2fce865b731..c4bf54bb3fc7 100644 --- a/trunk/drivers/serial/uartlite.c +++ b/trunk/drivers/serial/uartlite.c @@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); * Register definitions * * For register details see datasheet: - * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf + * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf */ #define ULITE_RX 0x00 diff --git a/trunk/drivers/staging/asus_oled/README b/trunk/drivers/staging/asus_oled/README index 0d82a6d5fa58..96b9717f168f 100644 --- a/trunk/drivers/staging/asus_oled/README +++ b/trunk/drivers/staging/asus_oled/README @@ -2,7 +2,7 @@ Driver for Asus OLED display present in some Asus laptops. The code of this driver is based on 'asusoled' program taken from - . I just wanted to have a simple + https://launchpad.net/asusoled/. I just wanted to have a simple kernel driver for controlling this device, but I didn't know how to do that. Now I know ;) Also, that program can not be used with usbhid loaded, which means no USB mouse/keyboard while diff --git a/trunk/drivers/staging/asus_oled/asus_oled.c b/trunk/drivers/staging/asus_oled/asus_oled.c index 8c95d8c2a4f4..5b279fb30f3f 100644 --- a/trunk/drivers/staging/asus_oled/asus_oled.c +++ b/trunk/drivers/staging/asus_oled/asus_oled.c @@ -24,7 +24,7 @@ * * * Asus OLED support is based on asusoled program taken from - * . + * https://launchpad.net/asusoled/. * * */ diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c b/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c index 78b1410ba4f6..ced346a7cae3 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -37,7 +37,7 @@ Configuration Options: Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org). Only supports DIO, AO and simple AI in it's present form. No interrupts, multi channel or FIFO AI, although the card looks like it could support this. -See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. +See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more details. */ #include "../comedidev.h" diff --git a/trunk/drivers/staging/comedi/drivers/daqboard2000.c b/trunk/drivers/staging/comedi/drivers/daqboard2000.c index 82be77daa7d7..6af6c8323d56 100644 --- a/trunk/drivers/staging/comedi/drivers/daqboard2000.c +++ b/trunk/drivers/staging/comedi/drivers/daqboard2000.c @@ -50,8 +50,8 @@ Configuration options: With some help from our swedish distributor, we got the Windows sourcecode for the card, and here are the findings so far. - 1. A good document that describes the PCI interface chip is 9080db-106.pdf - available from http://www.plxtech.com/products/io/pci9080 + 1. A good document that describes the PCI interface chip is found at: + http://plx.plxtech.com/download/9080/databook/9080db-106.pdf 2. The initialization done so far is: a. program the FPGA (windows code sans a lot of error messages) diff --git a/trunk/drivers/staging/comedi/drivers/ni_labpc.c b/trunk/drivers/staging/comedi/drivers/ni_labpc.c index 1411dd8f4e7c..3acf7e62bec4 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_labpc.c +++ b/trunk/drivers/staging/comedi/drivers/ni_labpc.c @@ -37,7 +37,7 @@ boards has not yet been added to the driver, mainly due to the fact that I don't know the device id numbers. If you have one of these boards, -please file a bug report at http://comedi.org/ +please file a bug report at https://bugs.comedi.org/ so I can get the necessary information from you. The 1200 series boards have onboard calibration dacs for correcting diff --git a/trunk/drivers/staging/comedi/drivers/ni_mio_common.c b/trunk/drivers/staging/comedi/drivers/ni_mio_common.c index 986ef6712989..bd16f913af23 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/trunk/drivers/staging/comedi/drivers/ni_mio_common.c @@ -34,7 +34,7 @@ 340747b.pdf AT-MIO E series Register Level Programmer Manual 341079b.pdf PCI E Series RLPM 340934b.pdf DAQ-STC reference manual - 67xx and 611x registers (from ftp://ftp.ni.com/support/daq/mhddk/documentation/) + 67xx and 611x registers (from http://www.ni.com/pdf/daq/us) release_ni611x.pdf release_ni67xx.pdf Other possibly relevant info: diff --git a/trunk/drivers/staging/comedi/drivers/plx9080.h b/trunk/drivers/staging/comedi/drivers/plx9080.h index 0d254a1b78a7..485d63f99293 100644 --- a/trunk/drivers/staging/comedi/drivers/plx9080.h +++ b/trunk/drivers/staging/comedi/drivers/plx9080.h @@ -13,7 +13,7 @@ * ******************************************************************** * - * Copyright (C) 1999 RG Studio s.c. + * Copyright (C) 1999 RG Studio s.c., http://www.rgstudio.com.pl/ * Written by Krzysztof Halasa * * Portions (C) SBE Inc., used by permission. diff --git a/trunk/drivers/staging/comedi/drivers/rtd520.c b/trunk/drivers/staging/comedi/drivers/rtd520.c index a49a7c566d37..0367d2b9e2fa 100644 --- a/trunk/drivers/staging/comedi/drivers/rtd520.c +++ b/trunk/drivers/staging/comedi/drivers/rtd520.c @@ -59,7 +59,7 @@ Configuration options: Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf Example source: http://www.rtdusa.com/examples/dm/dm7520.zip Call them and ask for the register level manual. - PCI chip: http://www.plxtech.com/products/io/pci9080 + PCI chip: http://www.plxtech.com/products/toolbox/9080.htm Notes: This board is memory mapped. There is some IO stuff, but it isn't needed. diff --git a/trunk/drivers/staging/quickstart/quickstart.c b/trunk/drivers/staging/quickstart/quickstart.c index ba8f670ec0a7..66122479d529 100644 --- a/trunk/drivers/staging/quickstart/quickstart.c +++ b/trunk/drivers/staging/quickstart/quickstart.c @@ -5,7 +5,8 @@ * Copyright (C) 2007-2010 Angelo Arrifano * * Information gathered from disassebled dsdt and from here: - * + * "http://download.microsoft.com/download/9/c/5/ + * 9c5b2167-8017-4bae-9fde-d599bac8184a/DirAppLaunch_Vista.doc" * * 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 diff --git a/trunk/drivers/uio/Kconfig b/trunk/drivers/uio/Kconfig index bb440792a1b7..1da73ecd9799 100644 --- a/trunk/drivers/uio/Kconfig +++ b/trunk/drivers/uio/Kconfig @@ -17,9 +17,9 @@ config UIO_CIF depends on PCI help Driver for Hilscher CIF DeviceNet and Profibus cards. This - driver requires a userspace component called cif that handles - all of the heavy lifting and can be found at: - + driver requires a userspace component that handles all of the + heavy lifting and can be found at: + http://www.osadl.org/projects/downloads/UIO/user/cif-* To compile this driver as a module, choose M here: the module will be called uio_cif. diff --git a/trunk/drivers/usb/gadget/at91_udc.c b/trunk/drivers/usb/gadget/at91_udc.c index bdec36acd0fa..387e503b9d14 100644 --- a/trunk/drivers/usb/gadget/at91_udc.c +++ b/trunk/drivers/usb/gadget/at91_udc.c @@ -1266,6 +1266,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) csr |= AT91_UDP_TXPKTRDY; __raw_writel(csr, creg); udc->req_pending = 0; + return; } static void handle_ep0(struct at91_udc *udc) diff --git a/trunk/drivers/usb/gadget/f_audio.c b/trunk/drivers/usb/gadget/f_audio.c index 00975ed903d1..1f48ceb55a77 100644 --- a/trunk/drivers/usb/gadget/f_audio.c +++ b/trunk/drivers/usb/gadget/f_audio.c @@ -317,6 +317,8 @@ static void f_audio_playback_work(struct work_struct *data) u_audio_playback(&audio->card, play_buf->buf, play_buf->actual); f_audio_buffer_free(play_buf); + + return; } static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) diff --git a/trunk/drivers/usb/gadget/f_hid.c b/trunk/drivers/usb/gadget/f_hid.c index 4f891eddd060..2b98bd26364b 100644 --- a/trunk/drivers/usb/gadget/f_hid.c +++ b/trunk/drivers/usb/gadget/f_hid.c @@ -318,6 +318,8 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&hidg->spinlock); wake_up(&hidg->read_queue); + + return; } static int hidg_setup(struct usb_function *f, @@ -411,6 +413,8 @@ static void hidg_disable(struct usb_function *f) usb_ep_disable(hidg->in_ep); hidg->in_ep->driver_data = NULL; + + return; } static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) diff --git a/trunk/drivers/usb/gadget/fsl_udc_core.c b/trunk/drivers/usb/gadget/fsl_udc_core.c index 4c55eda4bd20..c16b402a876b 100644 --- a/trunk/drivers/usb/gadget/fsl_udc_core.c +++ b/trunk/drivers/usb/gadget/fsl_udc_core.c @@ -287,6 +287,8 @@ static void dr_controller_run(struct fsl_udc *udc) temp = fsl_readl(&dr_regs->usbcmd); temp |= USB_CMD_RUN_STOP; fsl_writel(temp, &dr_regs->usbcmd); + + return; } static void dr_controller_stop(struct fsl_udc *udc) @@ -306,6 +308,8 @@ static void dr_controller_stop(struct fsl_udc *udc) tmp = fsl_readl(&dr_regs->usbcmd); tmp &= ~USB_CMD_RUN_STOP; fsl_writel(tmp, &dr_regs->usbcmd); + + return; } static void dr_ep_setup(unsigned char ep_num, unsigned char dir, @@ -412,6 +416,8 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, p_QH->max_pkt_length = cpu_to_le32(tmp); p_QH->next_dtd_ptr = 1; p_QH->size_ioc_int_sts = 0; + + return; } /* Setup qh structure and ep register for ep0. */ diff --git a/trunk/drivers/usb/gadget/pxa27x_udc.c b/trunk/drivers/usb/gadget/pxa27x_udc.c index 2efd6732d130..027d66f81620 100644 --- a/trunk/drivers/usb/gadget/pxa27x_udc.c +++ b/trunk/drivers/usb/gadget/pxa27x_udc.c @@ -1394,6 +1394,8 @@ static void pxa_ep_fifo_flush(struct usb_ep *_ep) } spin_unlock_irqrestore(&ep->lock, flags); + + return; } /** diff --git a/trunk/drivers/usb/gadget/rndis.c b/trunk/drivers/usb/gadget/rndis.c index d3cdffea9c8a..5b314041dfa9 100644 --- a/trunk/drivers/usb/gadget/rndis.c +++ b/trunk/drivers/usb/gadget/rndis.c @@ -918,6 +918,8 @@ void rndis_deregister(int configNr) if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params[configNr].used = 0; + + return; } int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) diff --git a/trunk/drivers/usb/host/ehci-hcd.c b/trunk/drivers/usb/host/ehci-hcd.c index 2adae8e39bba..15fe3ecd203b 100644 --- a/trunk/drivers/usb/host/ehci-hcd.c +++ b/trunk/drivers/usb/host/ehci-hcd.c @@ -1095,6 +1095,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ep->hcpriv = NULL; done: spin_unlock_irqrestore (&ehci->lock, flags); + return; } static void diff --git a/trunk/drivers/usb/host/imx21-hcd.c b/trunk/drivers/usb/host/imx21-hcd.c index e49b75a78000..1dfb2c8f7707 100644 --- a/trunk/drivers/usb/host/imx21-hcd.c +++ b/trunk/drivers/usb/host/imx21-hcd.c @@ -27,8 +27,8 @@ * * 32 transfer descriptors (called ETDs) * * 4Kb of Data memory * - * The data memory is shared between the host and function controllers - * (but this driver only supports the host controller) + * The data memory is shared between the host and fuction controlers + * (but this driver only supports the host controler) * * So setting up a transfer involves: * * Allocating a ETD diff --git a/trunk/drivers/usb/host/ohci-hcd.c b/trunk/drivers/usb/host/ohci-hcd.c index f3713f43f3fe..3b5785032a10 100644 --- a/trunk/drivers/usb/host/ohci-hcd.c +++ b/trunk/drivers/usb/host/ohci-hcd.c @@ -370,6 +370,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) } ep->hcpriv = NULL; spin_unlock_irqrestore (&ohci->lock, flags); + return; } static int ohci_get_frame (struct usb_hcd *hcd) diff --git a/trunk/drivers/usb/host/oxu210hp-hcd.c b/trunk/drivers/usb/host/oxu210hp-hcd.c index 32149be4ad8e..d32c3eae99cb 100644 --- a/trunk/drivers/usb/host/oxu210hp-hcd.c +++ b/trunk/drivers/usb/host/oxu210hp-hcd.c @@ -544,6 +544,8 @@ static void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd) qtd->buffer = NULL; spin_unlock(&oxu->mem_lock); + + return; } static inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma) @@ -569,6 +571,8 @@ static inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd) oxu->qtd_used[index] = 0; spin_unlock(&oxu->mem_lock); + + return; } static struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu) @@ -611,6 +615,8 @@ static void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh) oxu->qh_used[index] = 0; spin_unlock(&oxu->mem_lock); + + return; } static void qh_destroy(struct kref *kref) @@ -687,6 +693,8 @@ static void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb) oxu->murb_used[index] = 0; spin_unlock(&oxu->mem_lock); + + return; } static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu) @@ -3062,6 +3070,7 @@ static void oxu_endpoint_disable(struct usb_hcd *hcd, ep->hcpriv = NULL; done: spin_unlock_irqrestore(&oxu->lock, flags); + return; } static int oxu_get_frame(struct usb_hcd *hcd) diff --git a/trunk/drivers/usb/host/pci-quirks.c b/trunk/drivers/usb/host/pci-quirks.c index 4c502c890ebd..464ed977b45d 100644 --- a/trunk/drivers/usb/host/pci-quirks.c +++ b/trunk/drivers/usb/host/pci-quirks.c @@ -342,6 +342,8 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) writel(0x3f, op_reg_base + EHCI_USBSTS); iounmap(base); + + return; } /* diff --git a/trunk/drivers/usb/host/u132-hcd.c b/trunk/drivers/usb/host/u132-hcd.c index fab764946c74..5b31bae92dbc 100644 --- a/trunk/drivers/usb/host/u132-hcd.c +++ b/trunk/drivers/usb/host/u132-hcd.c @@ -316,6 +316,7 @@ static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) return; kref_put(&u132->kref, u132_hcd_delete); + return; } static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, @@ -323,6 +324,7 @@ static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, { kref_get(&u132->kref); u132_ring_requeue_work(u132, ring, delta); + return; } static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) @@ -541,6 +543,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, mutex_unlock(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); usb_hcd_giveback_urb(hcd, urb, status); + return; } static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, @@ -571,8 +574,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); + } usb_hcd_giveback_urb(hcd, urb, status); + return; } static inline int edset_input(struct u132 *u132, struct u132_ring *ring, @@ -3082,6 +3085,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->endp[endps] = NULL; mutex_unlock(&u132->sw_lock); + return; } static int __devinit u132_probe(struct platform_device *pdev) diff --git a/trunk/drivers/usb/image/microtek.c b/trunk/drivers/usb/image/microtek.c index 5a47805d9580..3a6bcd5fee09 100644 --- a/trunk/drivers/usb/image/microtek.c +++ b/trunk/drivers/usb/image/microtek.c @@ -398,6 +398,7 @@ void mts_int_submit_urb (struct urb* transfer, context->srb->result = DID_ERROR << 16; mts_transfer_cleanup(transfer); } + return; } @@ -408,6 +409,7 @@ static void mts_transfer_cleanup( struct urb *transfer ) if ( likely(context->final_callback != NULL) ) context->final_callback(context->srb); + } static void mts_transfer_done( struct urb *transfer ) @@ -418,6 +420,8 @@ static void mts_transfer_done( struct urb *transfer ) context->srb->result |= (unsigned)(*context->scsi_status)<<1; mts_transfer_cleanup(transfer); + + return; } @@ -448,6 +452,8 @@ static void mts_data_done( struct urb* transfer ) } mts_get_status(transfer); + + return; } @@ -490,6 +496,8 @@ static void mts_command_done( struct urb *transfer ) mts_get_status(transfer); } } + + return; } static void mts_do_sg (struct urb* transfer) @@ -514,6 +522,7 @@ static void mts_do_sg (struct urb* transfer) sg[context->fragment].length, context->fragment + 1 == scsi_sg_count(context->srb) ? mts_data_done : mts_do_sg); + return; } static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 }; diff --git a/trunk/drivers/usb/misc/ftdi-elan.c b/trunk/drivers/usb/misc/ftdi-elan.c index 7839c98fa742..c8eec9c2d89e 100644 --- a/trunk/drivers/usb/misc/ftdi-elan.c +++ b/trunk/drivers/usb/misc/ftdi-elan.c @@ -456,6 +456,7 @@ static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) { ftdi_command_queue_work(ftdi, 0); + return; } static void ftdi_elan_command_work(struct work_struct *work) @@ -482,6 +483,7 @@ static void ftdi_elan_command_work(struct work_struct *work) static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) { ftdi_respond_queue_work(ftdi, 0); + return; } static void ftdi_elan_respond_work(struct work_struct *work) diff --git a/trunk/drivers/usb/mon/mon_main.c b/trunk/drivers/usb/mon/mon_main.c index 10405119985c..812dc288bb8c 100644 --- a/trunk/drivers/usb/mon/mon_main.c +++ b/trunk/drivers/usb/mon/mon_main.c @@ -90,6 +90,7 @@ static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) r->rnf_submit(r->r_data, urb); } spin_unlock_irqrestore(&mbus->lock, flags); + return; } static void mon_submit(struct usb_bus *ubus, struct urb *urb) @@ -116,6 +117,7 @@ static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int erro r->rnf_error(r->r_data, urb, error); } spin_unlock_irqrestore(&mbus->lock, flags); + return; } static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) diff --git a/trunk/drivers/usb/serial/Kconfig b/trunk/drivers/usb/serial/Kconfig index c2b29761fa98..95058109f9fa 100644 --- a/trunk/drivers/usb/serial/Kconfig +++ b/trunk/drivers/usb/serial/Kconfig @@ -176,7 +176,7 @@ config USB_SERIAL_VISOR help Say Y here if you want to connect to your HandSpring Visor, Palm m500 or m505 through its USB docking station. See - for more information on using this + for more information on using this driver. To compile this driver as a module, choose M here: the @@ -289,7 +289,7 @@ config USB_SERIAL_KEYSPAN and was developed with their support. You must also include firmware to support your particular device(s). - See for more information. + See for more information. To compile this driver as a module, choose M here: the module will be called keyspan. diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index 2edf238b00b9..f5d06746cc3b 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -1320,6 +1320,8 @@ static void cypress_read_int_callback(struct urb *urb) cypress_set_dead(port); } } + + return; } /* cypress_read_int_callback */ diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index 89a9a5847803..37b57c785cc7 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -2108,6 +2108,7 @@ static void ftdi_set_termios(struct tty_struct *tty, } } + return; } static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) diff --git a/trunk/drivers/usb/serial/ftdi_sio_ids.h b/trunk/drivers/usb/serial/ftdi_sio_ids.h index 7dfe02f1fb6a..cf1aea1b9ee7 100644 --- a/trunk/drivers/usb/serial/ftdi_sio_ids.h +++ b/trunk/drivers/usb/serial/ftdi_sio_ids.h @@ -46,7 +46,7 @@ #define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */ /* OOCDlink by Joern Kaipf - * (http://www.joernonline.de/) */ + * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */ #define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ /* Luminary Micro Stellaris Boards, VID = FTDI_VID */ @@ -336,7 +336,7 @@ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ /* ACT Solutions HomePro ZWave interface - (http://www.act-solutions.com/HomePro-Product-Matrix.html) */ + (http://www.act-solutions.com/HomePro.htm) */ #define FTDI_ACTZWAVE_PID 0xF2D0 /* @@ -367,7 +367,7 @@ #define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ /* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ -/* http://www.usbuirt.com/ */ +/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */ #define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ /* CCS Inc. ICDU/ICDU40 product ID - @@ -396,7 +396,7 @@ */ #define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */ -/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */ +/* Inside Accesso contactless reader (http://www.insidefr.com) */ #define INSIDE_ACCESSO 0xFAD0 /* @@ -635,14 +635,14 @@ /* * JETI SPECTROMETER SPECBOS 1201 - * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101 + * http://www.jeti.com/products/sys/scb/scb1201.php */ #define JETI_VID 0x0c6c #define JETI_SPC1201_PID 0x04b2 /* * FTDI USB UART chips used in construction projects from the - * Elektor Electronics magazine (http://www.elektor.com/) + * Elektor Electronics magazine (http://elektor-electronics.co.uk) */ #define ELEKTOR_VID 0x0C7D #define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index 26710b189918..a42b29a695b2 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -1264,6 +1264,7 @@ static void garmin_read_bulk_callback(struct urb *urb) garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; spin_unlock_irqrestore(&garmin_data_p->lock, flags); } + return; } diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index cd769ef24f8a..a0ab78ada25e 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -1467,6 +1467,8 @@ static void edge_throttle(struct tty_struct *tty) if (status != 0) return; } + + return; } @@ -1773,6 +1775,8 @@ static void edge_break(struct tty_struct *tty, int break_state) dbg("%s - error sending break set/clear command.", __func__); } + + return; } @@ -2043,6 +2047,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, dbg("%s - Unrecognized IOSP status code %u", __func__, code); break; } + return; } @@ -2095,6 +2100,8 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) /* Save the new modem status */ edge_port->shadowMSR = newMsr & 0xf0; + + return; } @@ -2141,6 +2148,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, icount->parity++; if (newLsr & LSR_FRM_ERR) icount->frame++; + + return; } @@ -2716,6 +2725,7 @@ static void change_port_settings(struct tty_struct *tty, baud = tty_termios_baud_rate(old_termios); tty_encode_baud_rate(tty, baud, baud); } + return; } @@ -2917,6 +2927,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) 0x40, 0x4000, 0x0001, NULL, 0, 3000); release_firmware(fw); + return; } diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index 22506b095c4f..4dad27a0f22a 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -1571,6 +1571,8 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) } } tty_kref_put(tty); + + return; } static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, @@ -2422,6 +2424,7 @@ static void change_port_settings(struct tty_struct *tty, dbg("%s - error %d when trying to write config to device", __func__, status); kfree(config); + return; } static void edge_set_termios(struct tty_struct *tty, @@ -2442,6 +2445,7 @@ static void edge_set_termios(struct tty_struct *tty, return; /* change the port settings to the new ones specified */ change_port_settings(tty, edge_port, old_termios); + return; } static int edge_tiocmset(struct tty_struct *tty, struct file *file, diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index 12ed594f5f80..efc72113216b 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -807,6 +807,7 @@ static void read_rxcmd_callback(struct urb *urb) iuu_uart_read_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); dbg("%s - submit result = %d", __func__, result); + return; } static int iuu_uart_on(struct usb_serial_port *port) diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index 0791778a66f3..297163c3c610 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -9,7 +9,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - See http://blemings.org/hugh/keyspan.html for more information. + See http://misc.nu/hugh/keyspan.html for more information. Code in this driver inspired by and in a number of places taken from Brian Warner's original Keyspan-PDA driver. diff --git a/trunk/drivers/usb/serial/keyspan.h b/trunk/drivers/usb/serial/keyspan.h index 2d8baf6ac472..bf3297ddd186 100644 --- a/trunk/drivers/usb/serial/keyspan.h +++ b/trunk/drivers/usb/serial/keyspan.h @@ -9,7 +9,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - See http://blemings.org/hugh/keyspan.html for more information. + See http://misc.nu/hugh/keyspan.html for more information. Code in this driver inspired by and in a number of places taken from Brian Warner's original Keyspan-PDA driver. diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index a10dd5676ccc..185fe9a7d4e0 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -292,6 +292,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) port->interrupt_in_urb->dev = port->serial->dev; if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) dbg(" usb_submit_urb(read urb) failed"); + return; } diff --git a/trunk/drivers/usb/serial/mct_u232.h b/trunk/drivers/usb/serial/mct_u232.h index d325bb8cb583..3a3f5e6b8f96 100644 --- a/trunk/drivers/usb/serial/mct_u232.h +++ b/trunk/drivers/usb/serial/mct_u232.h @@ -10,9 +10,10 @@ * * This driver is for the device MCT USB-RS232 Converter (25 pin, Model No. * U232-P25) from Magic Control Technology Corp. (there is also a 9 pin - * Model No. U232-P9). See http://www.mct.com.tw/products/product_us232.html - * for further information. The properties of this device are listed at the end - * of this file. This device was used in the Dlink DSB-S25. + * Model No. U232-P9). See http://www.mct.com.tw/p_u232.html for further + * information. The properties of this device are listed at the end of this + * file. This device is available from various distributors. I know Hana, + * http://www.hana.de and D-Link, http://www.dlink.com/products/usb/dsbs25. * * All of the information about the device was acquired by using SniffUSB * on Windows98. The technical details of the reverse engineering are @@ -457,7 +458,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, * embedded UART. Exhaustive documentation for these is available at: * * http://www.semiconductors.philips.com/pip/p87c52ubaa - * http://www.nxp.com/acrobat_download/various/PDIUSBD12_PROGRAMMING_GUIDE.pdf + * http://www.semiconductors.philips.com/pip/pdiusbd12 * * Thanks to Julian Highfield for the pointer to the Philips database. * diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index 7d3bc9a3e2b6..fd0b6414f459 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -827,6 +827,7 @@ static void mos7720_interrupt_callback(struct urb *urb) dev_err(&urb->dev->dev, "%s - Error %d submitting control urb\n", __func__, result); + return; } /* @@ -906,6 +907,7 @@ static void mos7715_interrupt_callback(struct urb *urb) dev_err(&urb->dev->dev, "%s - Error %d submitting control urb\n", __func__, result); + return; } /* @@ -1225,6 +1227,8 @@ static void mos7720_break(struct tty_struct *tty, int break_state) mos7720_port->shadowLCR = data; write_mos_reg(serial, port->number - port->serial->minor, LCR, mos7720_port->shadowLCR); + + return; } /* @@ -1742,6 +1746,7 @@ static void change_port_settings(struct tty_struct *tty, dbg("usb_submit_urb(read bulk) failed, status = %d", status); } + return; } /* @@ -1798,6 +1803,7 @@ static void mos7720_set_termios(struct tty_struct *tty, dbg("usb_submit_urb(read bulk) failed, status = %d", status); } + return; } /* diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 5627993f9e41..93dad5853cd5 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -1367,6 +1367,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state) mos7840_port->shadowLCR); mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, mos7840_port->shadowLCR); + + return; } /***************************************************************************** @@ -1597,6 +1599,8 @@ static void mos7840_throttle(struct tty_struct *tty) if (status < 0) return; } + + return; } /***************************************************************************** @@ -2071,6 +2075,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty, mos7840_port->delta_msr_cond = 1; dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", mos7840_port->shadowLCR); + + return; } /***************************************************************************** @@ -2139,6 +2145,7 @@ static void mos7840_set_termios(struct tty_struct *tty, mos7840_port->read_urb_busy = false; } } + return; } /***************************************************************************** diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index 60f38d5e64fc..89c724c0ac0a 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -246,6 +246,8 @@ static void omninet_read_bulk_callback(struct urb *urb) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); + + return; } static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 7481ff8a49e4..d47b56e9e8ce 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -620,6 +620,8 @@ static void sierra_indat_callback(struct urb *urb) dev_err(&port->dev, "resubmit read urb failed." "(%d)\n", err); } + + return; } static void sierra_instat_callback(struct urb *urb) diff --git a/trunk/drivers/usb/serial/spcp8x5.c b/trunk/drivers/usb/serial/spcp8x5.c index 765aa983bf58..329d311a35d9 100644 --- a/trunk/drivers/usb/serial/spcp8x5.c +++ b/trunk/drivers/usb/serial/spcp8x5.c @@ -441,6 +441,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, spcp8x5_set_workMode(serial->dev, 0x000a, SET_WORKING_MODE_U2C, priv->type); } + return; } /* open the serial port. do some usb system call. set termios and get the line diff --git a/trunk/drivers/usb/serial/usb_wwan.c b/trunk/drivers/usb/serial/usb_wwan.c index fbc946797801..0c70b4a621bb 100644 --- a/trunk/drivers/usb/serial/usb_wwan.c +++ b/trunk/drivers/usb/serial/usb_wwan.c @@ -234,6 +234,7 @@ static void usb_wwan_indat_callback(struct urb *urb) } } + return; } static void usb_wwan_outdat_callback(struct urb *urb) diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 3f9ac88d588c..12ed8209ca72 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -655,6 +655,8 @@ static void whiteheat_release(struct usb_serial *serial) } kfree(info); } + + return; } static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -953,6 +955,8 @@ static void whiteheat_throttle(struct tty_struct *tty) spin_lock_irq(&info->lock); info->flags |= THROTTLED; spin_unlock_irq(&info->lock); + + return; } @@ -971,6 +975,8 @@ static void whiteheat_unthrottle(struct tty_struct *tty) if (actually_throttled) rx_data_softint(&info->rx_work); + + return; } diff --git a/trunk/drivers/usb/storage/Kconfig b/trunk/drivers/usb/storage/Kconfig index 49a489e03716..f2767cf2e229 100644 --- a/trunk/drivers/usb/storage/Kconfig +++ b/trunk/drivers/usb/storage/Kconfig @@ -36,7 +36,7 @@ config USB_STORAGE_DATAFAB depends on USB_STORAGE help Support for certain Datafab CompactFlash readers. - Datafab has a web page at . + Datafab has a web page at . If this driver is compiled as a module, it will be named ums-datafab. diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index dc06ff134559..8b31fdfefc98 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -49,7 +49,7 @@ menuconfig FB You need an utility program called fbset to make full use of frame buffer devices. Please read and the Framebuffer-HOWTO at - for more + for more information. Say Y here and to the driver for your graphics board below if you @@ -955,7 +955,7 @@ config FB_EPSON1355 Build in support for the SED1355 Epson Research Embedded RAMDAC LCD/CRT Controller (since redesignated as the S1D13505) as a framebuffer. Product specs at - . + . config FB_S1D13XXX tristate "Epson S1D13XXX framebuffer support" @@ -966,7 +966,7 @@ config FB_S1D13XXX help Support for S1D13XXX framebuffer device family (currently only working with S1D13806). Product specs at - + config FB_ATMEL tristate "AT91/AT32 LCD Controller support" @@ -1323,7 +1323,7 @@ config FB_RADEON don't need to choose this to run the Radeon in plain VGA mode. There is a product page at - http://products.amd.com/en-us/GraphicCardResult.aspx + http://apps.ati.com/ATIcompare/ config FB_RADEON_I2C bool "DDC/I2C for ATI Radeon support" @@ -1395,7 +1395,7 @@ config FB_ATY_CT Say Y here to support use of ATI's 64-bit Rage boards (or other boards based on the Mach64 CT, VT, GT, and LT chipsets) as a framebuffer device. The ATI product support page for these boards - is at . + is at . config FB_ATY_GENERIC_LCD bool "Mach64 generic LCD support (EXPERIMENTAL)" diff --git a/trunk/drivers/video/arcfb.c b/trunk/drivers/video/arcfb.c index 3ec4923c2d84..f3d7440f0072 100644 --- a/trunk/drivers/video/arcfb.c +++ b/trunk/drivers/video/arcfb.c @@ -2,6 +2,7 @@ * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board * * Copyright (C) 2005, Jaya Kumar + * http://www.intworks.biz/arclcd * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for diff --git a/trunk/drivers/video/aty/radeon_i2c.c b/trunk/drivers/video/aty/radeon_i2c.c index 78d1f4cd1fe0..359fc64e761a 100644 --- a/trunk/drivers/video/aty/radeon_i2c.c +++ b/trunk/drivers/video/aty/radeon_i2c.c @@ -7,6 +7,7 @@ #include +#include #include #include diff --git a/trunk/drivers/video/bf54x-lq043fb.c b/trunk/drivers/video/bf54x-lq043fb.c index e7d0f525041e..b020ba7f1cf2 100644 --- a/trunk/drivers/video/bf54x-lq043fb.c +++ b/trunk/drivers/video/bf54x-lq043fb.c @@ -241,12 +241,12 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) u16 disp = fbi->mach_info->disp; if (gpio_request(disp, DRIVER_NAME)) { - printk(KERN_ERR "Requesting GPIO %d failed\n", disp); + printk(KERN_ERR "Requesting GPIO %d faild\n", disp); return -EFAULT; } if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) { - printk(KERN_ERR "Requesting Peripherals failed\n"); + printk(KERN_ERR "Requesting Peripherals faild\n"); gpio_free(disp); return -EFAULT; } @@ -256,7 +256,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) u16 eppi_req_24[] = EPPI0_24; if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) { - printk(KERN_ERR "Requesting Peripherals failed\n"); + printk(KERN_ERR "Requesting Peripherals faild\n"); peripheral_free_list(eppi_req_18); gpio_free(disp); return -EFAULT; diff --git a/trunk/drivers/video/bfin-t350mcqb-fb.c b/trunk/drivers/video/bfin-t350mcqb-fb.c index 3cf77676947c..7a50272eaab9 100644 --- a/trunk/drivers/video/bfin-t350mcqb-fb.c +++ b/trunk/drivers/video/bfin-t350mcqb-fb.c @@ -192,7 +192,7 @@ static int bfin_t350mcqb_request_ports(int action) { if (action) { if (peripheral_request_list(ppi0_req_8, DRIVER_NAME)) { - printk(KERN_ERR "Requesting Peripherals failed\n"); + printk(KERN_ERR "Requesting Peripherals faild\n"); return -EFAULT; } } else diff --git a/trunk/drivers/video/epson1355fb.c b/trunk/drivers/video/epson1355fb.c index a268cbf1cbea..db9713b49ce9 100644 --- a/trunk/drivers/video/epson1355fb.c +++ b/trunk/drivers/video/epson1355fb.c @@ -4,7 +4,7 @@ * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller * (previously known as SED1355) * - * Cf. http://vdc.epson.com/ + * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html * * * Copyright (C) Hewlett-Packard Company. All rights reserved. diff --git a/trunk/drivers/video/fbcvt.c b/trunk/drivers/video/fbcvt.c index 7cb715dfc0e1..7293eaccd81b 100644 --- a/trunk/drivers/video/fbcvt.c +++ b/trunk/drivers/video/fbcvt.c @@ -5,7 +5,7 @@ * * Based from the VESA(TM) Coordinated Video Timing Generator by * Graham Loveridge April 9, 2003 available at - * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls + * http://www.vesa.org/public/CVT/CVTd6r1.xls * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive diff --git a/trunk/drivers/video/i810/i810.h b/trunk/drivers/video/i810/i810.h index f37de60ecc59..328ae6c673ec 100644 --- a/trunk/drivers/video/i810/i810.h +++ b/trunk/drivers/video/i810/i810.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include