From: Marc Fiuczynski Date: Mon, 12 Jul 2004 21:57:21 +0000 (+0000) Subject: This commit was generated by cvs2svn to compensate for changes in r37, X-Git-Tag: before-ipod-patch~23 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=39b607ac274a09883c7fe5f03a7eff28960a1190;p=linux-2.6.git This commit was generated by cvs2svn to compensate for changes in r37, which included commits to RCS files with non-trunk default branches. --- diff --git a/Documentation/arm/IXP4xx b/Documentation/arm/IXP4xx new file mode 100644 index 000000000..d86d818a4 --- /dev/null +++ b/Documentation/arm/IXP4xx @@ -0,0 +1,155 @@ + +------------------------------------------------------------------------- +Release Notes for Linux on Intel's IXP4xx Network Processor + +Maintained by Deepak Saxena +------------------------------------------------------------------------- + +1. Overview + +Intel's IXP4xx network processor is a highly integrated SOC that +is targeted for network applications, though it has become popular +in industrial control and other areas due to low cost and power +consumption. The IXP4xx family currently consists of several processors +that support different network offload functions such as encryption, +routing, firewalling, etc. For more information on the various +versions of the CPU, see: + + http://developer.intel.com/design/network/products/npfamily/ixp4xx.htm + +Intel also made the IXCP1100 CPU for sometime which is an IXP4xx +stripped of much of the network intelligence. + +2. Linux Support + +Linux currently supports the following features on the IXP4xx chips: + +- Dual serial ports +- PCI interface +- Flash access (MTD/JFFS) +- I2C through GPIO +- GPIO for input/output/interrupts + See include/asm-arm/arch-ixp4xx/platform.h for access functions. +- Timers (watchdog, OS) + +The following components of the chips are not supported by Linux and +require the use of Intel's propietary CSR softare: + +- USB device interface +- Network interfaces (HSS, Utopia, NPEs, etc) +- Network offload functionality + +If you need to use any of the above, you need to download Intel's +software from: + + http://developer.intel.com/design/network/products/npfamily/ixp425swr1.htm + +DO NOT POST QUESTIONS TO THE LINUX MAILING LISTS REGARDING THE PROPIETARY +SOFTWARE. + +There are several websites that provide directions/pointers on using +Intel's software: + +http://ixp4xx-osdg.sourceforge.net/ + Open Source Developer's Guide for using uClinux and the Intel libraries + +http://gatewaymaker.sourceforge.net/ + Simple one page summary of building a gateway using an IXP425 and Linux + +http://ixp425.sourceforge.net/ + ATM device driver for IXP425 that relies on Intel's libraries + +3. Known Issues/Limitations + +3a. Limited inbound PCI window + +The IXP4xx family allows for up to 256MB of memory but the PCI interface +can only expose 64MB of that memory to the PCI bus. This means that if +you are running with > 64MB, all PCI buffers outside of the accessible +range will be bounced using the routines in arch/arm/common/dmabounce.c. + +3b. Limited outbound PCI window + +IXP4xx provides two methods of accessing PCI memory space: + +1) A direct mapped window from 0x48000000 to 0x4bffffff (64MB). + To access PCI via this space, we simply ioremap() the BAR + into the kernel and we can use the standard read[bwl]/write[bwl] + macros. This is the preffered method due to speed but it + limits the system to just 64MB of PCI memory. This can be + problamatic if using video cards and other memory-heavy devices. + +2) If > 64MB of memory space is required, the IXP4xx can be + configured to use indirect registers to access PCI This allows + for up to 128MB (0x48000000 to 0x4fffffff) of memory on the bus. + The disadvantadge of this is that every PCI access requires + three local register accesses plus a spinlock, but in some + cases the performance hit is acceptable. In addition, you cannot + mmap() PCI devices in this case due to the indirect nature + of the PCI window. + +By default, the direct method is used for performance reasons. If +you need more PCI memory, enable the IXP4XX_INDIRECT_PCI config option. + +3c. GPIO as Interrupts + +Currently the code only handles level-sensitive GPIO interrupts + +4. Supported platforms + +ADI Engineering Coyote Gateway Reference Platform +http://www.adiengineering.com/productsCoyote.html + + The ADI Coyote platform is reference design for those building + small residential/office gateways. One NPE is connected to a 10/100 + interface, one to 4-port 10/100 switch, and the third to and ADSL + interface. In addition, it also supports to POTs interfaces connected + via SLICs. Note that those are not supported by Linux ATM. Finally, + the platform has two mini-PCI slots used for 802.11[bga] cards. + Finally, there is an IDE port hanging off the expansion bus. + +Gateworks Avila Network Platform +http://www.gateworks.com/avila_sbc.htm + + The Avila platform is basically and IXDP425 with the 4 PCI slots + replaced with mini-PCI slots and a CF IDE interface hanging off + the expansion bus. + +Intel IXDP425 Development Platform +http://developer.intel.com/design/network/products/npfamily/ixdp425.htm + + This is Intel's standard reference platform for the IXDP425 and is + also known as the Richfield board. It contains 4 PCI slots, 16MB + of flash, two 10/100 ports and one ADSL port. + +Motorola PrPMC1100 Processor Mezanine Card +http://www.fountainsys.com/datasheet/PrPMC1100.pdf + + The PrPMC1100 is based on the IXCP1100 and is meant to plug into + and IXP2400/2800 system to act as the system controller. It simply + contains a CPU and 16MB of flash on the board and needs to be + plugged into a carrier board to function. Currently Linux only + supports the Motorola PrPMC carrier board for this platform. + See https://mcg.motorola.com/us/ds/pdf/ds0144.pdf for info + on the carrier board. + +5. TODO LIST + +- Add support for Coyote IDE +- Add support for edge-based GPIO interrupts +- Add support for CF IDE on expansion bus + +6. Thanks + +The IXP4xx work has been funded by Intel Corp. and MontaVista Software, Inc. + +The following people have contributed patches/comments/etc: + +Lutz Jaenicke +Justin Mayfield +Robert E. Ranslam +[I know I've forgotten others, please email me to be added] + +------------------------------------------------------------------------- + +Last Update: 5/13/2004 diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt index 967ce6c56..4b1c93a81 100644 --- a/Documentation/arm/memory.txt +++ b/Documentation/arm/memory.txt @@ -1,7 +1,7 @@ Kernel Memory Layout on ARM Linux Russell King - April 27, 2003 (2.5.68) + May 21, 2004 (2.6.6) This document describes the virtual memory layout which the Linux kernel uses for ARM processors. It indicates which regions are @@ -29,32 +29,30 @@ ffff0000 ffff0fff CPU vector page. CPU supports vector relocation (control register V bit.) -ffe00000 fffeffff Free for platform use, not recommended. +ffc00000 fffeffff DMA memory mapping region. Memory returned + by the dma_alloc_xxx functions will be + dynamically mapped here. -ffc00000 ffdfffff 2MB consistent memory mapping. - Memory returned by the consistent_alloc - low level function will be dynamically - mapped here. +ff000000 ffbfffff Reserved for future expansion of DMA + mapping region. -ff000000 ffbfffff Free for platform use, not recommended. +VMALLOC_END feffffff Free for platform use, recommended. -VMALLOC_END ff000000 Free for platform use, recommended. - -VMALLOC_START VMALLOC_END vmalloc() / ioremap() space. +VMALLOC_START VMALLOC_END-1 vmalloc() / ioremap() space. Memory returned by vmalloc/ioremap will be dynamically placed in this region. VMALLOC_START may be based upon the value of the high_memory variable. -PAGE_OFFSET high_memory Kernel direct-mapped RAM region. +PAGE_OFFSET high_memory-1 Kernel direct-mapped RAM region. This maps the platforms RAM, and typically maps all platform RAM in a 1:1 relationship. -TASK_SIZE PAGE_OFFSET Kernel module space +TASK_SIZE PAGE_OFFSET-1 Kernel module space Kernel modules inserted via insmod are placed here using dynamic mappings. -00001000 TASK_SIZE User space mappings +00001000 TASK_SIZE-1 User space mappings Per-thread mappings are placed here via the mmap() system call. diff --git a/Documentation/cpu-freq/amd-powernow.txt b/Documentation/cpu-freq/amd-powernow.txt new file mode 100644 index 000000000..254da155f --- /dev/null +++ b/Documentation/cpu-freq/amd-powernow.txt @@ -0,0 +1,38 @@ + +PowerNow! and Cool'n'Quiet are AMD names for frequency +management capabilities in AMD processors. As the hardware +implementation changes in new generations of the processors, +there is a different cpu-freq driver for each generation. + +Note that the driver's will not load on the "wrong" hardware, +so it is safe to try each driver in turn when in doubt as to +which is the correct driver. + +Note that the functionality to change frequency (and voltage) +is not available in all processors. The drivers will refuse +to load on processors without this capability. The capability +is detected with the cpuid instruction. + +The drivers use BIOS supplied tables to obtain frequency and +voltage information appropriate for a particular platform. +Frequency transitions will be unavailable if the BIOS does +not supply these tables. + +6th Generation: powernow-k6 + +7th Generation: powernow-k7: Athlon, Duron, Geode. + +8th Generation: powernow-k8: Athlon, Athlon 64, Opteron, Sempron. +Documentation on this functionality in 8th generation processors +is available in the "BIOS and Kernel Developer's Guide", publication +26094, in chapter 9, available for download from www.amd.com. + +BIOS supplied data, for powernow-k7 and for powernow-k8, may be +from either the PSB table or from ACPI objects. The ACPI support +is only available if the kernel config sets CONFIG_ACPI_PROCESSOR. +The powernow-k8 driver will attempt to use ACPI if so configured, +and fall back to PST if that fails. +The powernow-k7 driver will try to use the PSB support first, and +fall back to ACPI if the PSB support fails. A module parameter, +acpi_force, is provided to force ACPI support to be used instead +of PSB support. diff --git a/Documentation/fb/framebuffer.txt b/Documentation/fb/framebuffer.txt index b8d0b78f4..610e78012 100644 --- a/Documentation/fb/framebuffer.txt +++ b/Documentation/fb/framebuffer.txt @@ -190,7 +190,7 @@ We'll say that the horizontal scanrate is about 31 kHz: 1/(32.141E-6 s) = 31.113E3 Hz A full screen counts 480 (yres) lines, but we have to consider the vertical -retrace too (e.g. 49 `pixels'). So a full screen will take +retrace too (e.g. 49 `lines'). So a full screen will take (480+49)*32.141E-6 s = 17.002E-3 s diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting index 548dcf48e..31047e0fe 100644 --- a/Documentation/filesystems/Exporting +++ b/Documentation/filesystems/Exporting @@ -32,7 +32,7 @@ tree. This means that if any filesystem object is in the dcache, then all of the ancestors of that filesystem object are also in the dcache. As normal access is by filename this prefix is created naturally and maintained easily (by each object maintaining a reference count on -it's parent). +its parent). However when objects are included into the dcache by interpreting a filehandle fragment, there is no automatic creation of a path prefix @@ -44,15 +44,15 @@ the dcache that are not needed for normal filesystem access. 2/ The dcache must be prepared for a newly found (via ->lookup) directory to already have a (non-connected) dentry, and must be able to move that dentry into place (based on the parent and name in the - ->lookup). This is particuarly needed for directories as + ->lookup). This is particularly needed for directories as it is a dcache invariant that directories only have one dentry. To implement these features, the dcache has: -a/ A dentry flag DCACHE_DISCONNECTED which is set on - and dentry that might not be part of the proper prefix. +a/ A dentry flag DCACHE_DISCONNECTED which is set on + any dentry that might not be part of the proper prefix. This is set when anonymous dentries are created, and cleared when a - dentry is noticed to be a child on a dentry which is in the proper + dentry is noticed to be a child of a dentry which is in the proper prefix. b/ A per-superblock list "s_anon" of dentries which are the roots of @@ -123,9 +123,9 @@ filesystem: get_name. When given a parent dentry and a child dentry, this should find a name in the directory identified by the parent dentry, which leads to the object identified by the child dentry. - If no get_name function is supplied, a default implementation - which used vfs_readdir to find potential names, and matches inode - numbers to find the correct match. + If no get_name function is supplied, a default implementation is + provided which uses vfs_readdir to find potential names, and + matches inode numbers to find the correct match. get_parent. When given a dentry for a directory, this should return a dentry for the parent. Quite possibly the parent dentry will @@ -135,7 +135,7 @@ filesystem: ->lookup("..") is *not* used as a default as it can leave ".." entries in the dcache which are too messy to work with. - get_dentry. When given a opaque datum, this should find the + get_dentry. When given an opaque datum, this should find the implied object and create a dentry for it (possibly with d_alloc_anon). The opaque datum is whatever is passed down by the decode_fh @@ -143,7 +143,7 @@ filesystem: fragment. decode_fh passes two datums through find_exported_dentry. One that should be used to identify the target object, and one that can be - used to identify the objects parent, should that be necessary. + used to identify the object's parent, should that be necessary. The default get_dentry function assumes that the datum contains an inode number and a generation number, and it attempts to get the inode using "iget" and check it's validity by matching the @@ -164,8 +164,8 @@ filehandle assuming the format used by the default encode_fh and passed them to find_exported_dentry. -A filehandle fragment consists of an array of 1 or more 4byte words. -Together with a one byte "type". +A filehandle fragment consists of an array of 1 or more 4byte words, +together with a one byte "type". The decode_fh routine should not depend on the stated size that is passed to it. This size may be larger than the original filehandle generated by encode_fh, in which case it will have been padded with diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 83e6a8f83..e0ef1f80f 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -203,20 +203,34 @@ currently-in-progress I/O. If the filesystem is not called for "sync" and it determines that it would need to block against in-progress I/O to be able to start new I/O -against the page the filesystem shoud redirty the page (usually with -__set_page_dirty_nobuffers()), then unlock the page and return zero. +against the page the filesystem should redirty the page with +redirty_page_for_writepage(), then unlock the page and return zero. This may also be done to avoid internal deadlocks, but rarely. If the filesytem is called for sync then it must wait on any in-progress I/O and then start new I/O. The filesystem should unlock the page synchronously, before returning -to the caller. If the page has write I/O underway against it, -writepage() should run SetPageWriteback() against the page prior to -unlocking it. The write I/O completion handler should run -end_page_writeback() against the page. - -That is: after 2.5.12, pages which are under writeout are *not* locked. +to the caller. + +Unless the filesystem is going to redirty_page_for_writepage(), unlock the page +and return zero, writepage *must* run set_page_writeback() against the page, +followed by unlocking it. Once set_page_writeback() has been run against the +page, write I/O can be submitted and the write I/O completion handler must run +end_page_writeback() once the I/O is complete. If no I/O is submitted, the +filesystem must run end_page_writeback() against the page before returning from +writepage. + +That is: after 2.5.12, pages which are under writeout are *not* locked. Note, +if the filesystem needs the page to be locked during writeout, that is ok, too, +the page is allowed to be unlocked at any point in time between the calls to +set_page_writeback() and end_page_writeback(). + +Note, failure to run either redirty_page_for_writepage() or the combination of +set_page_writeback()/end_page_writeback() on a page submitted to writepage +will leave the page itself marked clean but it will be tagged as dirty in the +radix tree. This incoherency can lead to all sorts of hard-to-debug problems +in the filesystem like having dirty inodes at umount and losing written data. ->sync_page() locking rules are not well-defined - usually it is called with lock on page, but that is not guaranteed. Considering the currently diff --git a/Documentation/ide.txt b/Documentation/ide.txt index 07811d2df..58853a4ef 100644 --- a/Documentation/ide.txt +++ b/Documentation/ide.txt @@ -248,6 +248,13 @@ Summary of ide driver parameters for kernel command line allowing ide-floppy, ide-tape, and ide-cdrom|writers to use ide-scsi emulation on a device specific option. + "hdx=stroke" : Should you have a system w/ an AWARD Bios and your + drives are larger than 32GB and it will not boot, + one is required to perform a few OEM operations first. + The option is called "stroke" because it allows one + to "soft clip" the drive to work around a barrier + limit. + "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, where "xx" is between 20 and 66 inclusive, used when tuning chipset PIO modes. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 591e458ee..c26a38ac5 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -896,8 +896,8 @@ running once the system is up. psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports per second. psmouse.resetafter= - [HW,MOUSE] Try to reset Synaptics Touchpad after so many - bad packets (0 = never). + [HW,MOUSE] Try to reset the device after so many bad packets + (0 = never). psmouse.resolution= [HW,MOUSE] Set desired mouse resolution, in dpi. psmouse.smartscroll= diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 091b2d202..8d4cf7825 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -1,11 +1,3 @@ - -DaveM: - -If you agree with it I will send two small patches to modify -kernel's configure help. - - Ulisses - -------------------------------------------------------------------------------- + ABSTRACT -------------------------------------------------------------------------------- @@ -405,8 +397,3 @@ then poll for frames. Jesse Brandeburg, for fixing my grammathical/spelling errors ->>> EOF -- -To unsubscribe from this list: send the line "unsubscribe linux-net" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/Documentation/sound/alsa/Audigy-mixer.txt b/Documentation/sound/alsa/Audigy-mixer.txt new file mode 100644 index 000000000..5132fd95e --- /dev/null +++ b/Documentation/sound/alsa/Audigy-mixer.txt @@ -0,0 +1,345 @@ + + Sound Blaster Audigy mixer / default DSP code + =========================================== + +This is based on SB-Live-mixer.txt. + +The EMU10K2 chips have a DSP part which can be programmed to support +various ways of sample processing, which is described here. +(This acticle does not deal with the overall functionality of the +EMU10K2 chips. See the manuals section for further details.) + +The ALSA driver programs this portion of chip by default code +(can be altered later) which offers the following functionality: + + +1) Digital mixer controls +------------------------- + +These controls are built using the DSP instructions. They offer extended +functionality. Only the default build-in code in the ALSA driver is described +here. Note that the controls work as attenuators: the maximum value is the +neutral position leaving the signal unchanged. Note that if the same destination +is mentioned in multiple controls, the signal is accumulated and can be wrapped +(set to maximal or minimal value without checking of overflow). + + +Explanation of used abbreviations: + +DAC - digital to analog converter +ADC - analog to digital converter +I2S - one-way three wire serial bus for digital sound by Philips Semiconductors + (this standard is used for connecting standalone DAC and ADC converters) +LFE - low frequency effects (subwoofer signal) +AC97 - a chip containing an analog mixer, DAC and ADC converters +IEC958 - S/PDIF +FX-bus - the EMU10K2 chip has an effect bus containing 64 accumulators. + Each of the synthesizer voices can feed its output to these accumulators + and the DSP microcontroller can operate with the resulting sum. + +name='PCM Front Playback Volume',index=0 + +This control is used to attenuate samples for left and right front PCM FX-bus +accumulators. ALSA uses accumulators 8 and 9 for left and right front PCM +samples for 5.1 playback. The result samples are forwarded to the front DAC PCM +slots of the Philips DAC. + +name='PCM Surround Playback Volume',index=0 + +This control is used to attenuate samples for left and right surround PCM FX-bus +accumulators. ALSA uses accumulators 2 and 3 for left and right surround PCM +samples for 5.1 playback. The result samples are forwarded to the surround DAC PCM +slots of the Philips DAC. + +name='PCM Center Playback Volume',index=0 + +This control is used to attenuate samples for center PCM FX-bus accumulator. +ALSA uses accumulator 6 for center PCM sample for 5.1 playback. The result sample +is forwarded to the center DAC PCM slot of the Philips DAC. + +name='PCM LFE Playback Volume',index=0 + +This control is used to attenuate sample for LFE PCM FX-bus accumulator. +ALSA uses accumulator 7 for LFE PCM sample for 5.1 playback. The result sample +is forwarded to the LFE DAC PCM slot of the Philips DAC. + +name='PCM Playback Volume',index=0 + +This control is used to attenuate samples for left and right PCM FX-bus +accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples for +stereo playback. The result samples are forwarded to the front DAC PCM slots +of the Philips DAC. + +name='PCM Capture Volume',index=0 + +This control is used to attenuate samples for left and right PCM FX-bus +accumulator. ALSA uses accumulators 0 and 1 for left and right PCM. +The result is forwarded to the ADC capture FIFO (thus to the standard capture +PCM device). + +name='Music Playback Volume',index=0 + +This control is used to attenuate samples for left and right MIDI FX-bus +accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. +The result samples are forwarded to the front DAC PCM slots of the AC97 codec. + +name='Music Capture Volume',index=0 + +These controls are used to attenuate samples for left and right MIDI FX-bus +accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. +The result is forwarded to the ADC capture FIFO (thus to the standard capture +PCM device). + +name='Mic Playback Volume',index=0 + +This control is used to attenuate samples for left and right Mic input. +For Mic input is used AC97 codec. The result samples are forwarded to +the front DAC PCM slots of the Philips DAC. Samples are forwarded to Mic +capture FIFO (device 1 - 16bit/8KHz mono) too without volume control. + +name='Mic Capture Volume',index=0 + +This control is used to attenuate samples for left and right Mic input. +The result is forwarded to the ADC capture FIFO (thus to the standard capture +PCM device). + +name='Audigy CD Playback Volume',index=0 + +This control is used to attenuate samples from left and right IEC958 TTL +digital inputs (usually used by a CDROM drive). The result samples are +forwarded to the front DAC PCM slots of the Philips DAC. + +name='Audigy CD Capture Volume',index=0 + +This control is used to attenuate samples from left and right IEC958 TTL +digital inputs (usually used by a CDROM drive). The result samples are +forwarded to the ADC capture FIFO (thus to the standard capture PCM device). + +name='IEC958 Optical Playback Volume',index=0 + +This control is used to attenuate samples from left and right IEC958 optical +digital input. The result samples are forwarded to the front DAC PCM slots +of the Philips DAC. + +name='IEC958 Optical Capture Volume',index=0 + +This control is used to attenuate samples from left and right IEC958 optical +digital inputs. The result samples are forwarded to the ADC capture FIFO +(thus to the standard capture PCM device). + +name='Line2 Playback Volume',index=0 + +This control is used to attenuate samples from left and right I2S ADC +inputs (on the AudigyDrive). The result samples are forwarded to the front +DAC PCM slots of the Philips DAC. + +name='Line2 Capture Volume',index=1 + +This control is used to attenuate samples from left and right I2S ADC +inputs (on the AudigyDrive). The result samples are forwarded to the ADC +capture FIFO (thus to the standard capture PCM device). + +name='Analog Mix Playback Volume',index=0 + +This control is used to attenuate samples from left and right I2S ADC +inputs from Philips ADC. The result samples are forwarded to the front +DAC PCM slots of the Philips DAC. This contains mix from analog sources +like CD, Line In, Aux, .... + +name='Analog Mix Capture Volume',index=1 + +This control is used to attenuate samples from left and right I2S ADC +inputs Philips ADC. The result samples are forwarded to the ADC +capture FIFO (thus to the standard capture PCM device). + +name='Aux2 Playback Volume',index=0 + +This control is used to attenuate samples from left and right I2S ADC +inputs (on the AudigyDrive). The result samples are forwarded to the front +DAC PCM slots of the Philips DAC. + +name='Aux2 Capture Volume',index=1 + +This control is used to attenuate samples from left and right I2S ADC +inputs (on the AudigyDrive). The result samples are forwarded to the ADC +capture FIFO (thus to the standard capture PCM device). + +name='Front Playback Volume',index=0 + +All stereo signals are mixed together and mirrored to surround, center and LFE. +This control is used to attenuate samples for left and right front speakers of +this mix. + +name='Surround Playback Volume',index=0 + +All stereo signals are mixed together and mirrored to surround, center and LFE. +This control is used to attenuate samples for left and right surround speakers of +this mix. + +name='Center Playback Volume',index=0 + +All stereo signals are mixed together and mirrored to surround, center and LFE. +This control is used to attenuate sample for center speaker of this mix. + +name='LFE Playback Volume',index=0 + +All stereo signals are mixed together and mirrored to surround, center and LFE. +This control is used to attenuate sample for LFE speaker of this mix. + +name='Tone Control - Switch',index=0 + +This control turns the tone control on or off. The samples for front, rear +and center / LFE outputs are affected. + +name='Tone Control - Bass',index=0 + +This control sets the bass intensity. There is no neutral value!! +When the tone control code is activated, the samples are always modified. +The closest value to pure signal is 20. + +name='Tone Control - Treble',index=0 + +This control sets the treble intensity. There is no neutral value!! +When the tone control code is activated, the samples are always modified. +The closest value to pure signal is 20. + +name='Master Playback Volume',index=0 + +This control is used to attenuate samples for front, surround, center and +LFE outputs. + +name='IEC958 Optical Raw Playback Switch',index=0 + +If this switch is on, then the samples for the IEC958 (S/PDIF) digital +output are taken only from the raw FX8010 PCM, otherwise standard front +PCM samples are taken. + + +2) PCM stream related controls +------------------------------ + +name='EMU10K1 PCM Volume',index 0-31 + +Channel volume attenuation in range 0-0xffff. The maximum value (no +attenuation) is default. The channel mapping for three values is +as follows: + + 0 - mono, default 0xffff (no attenuation) + 1 - left, default 0xffff (no attenuation) + 2 - right, default 0xffff (no attenuation) + +name='EMU10K1 PCM Send Routing',index 0-31 + +This control specifies the destination - FX-bus accumulators. There 24 +values with this mapping: + + 0 - mono, A destination (FX-bus 0-63), default 0 + 1 - mono, B destination (FX-bus 0-63), default 1 + 2 - mono, C destination (FX-bus 0-63), default 2 + 3 - mono, D destination (FX-bus 0-63), default 3 + 4 - mono, E destination (FX-bus 0-63), default 0 + 5 - mono, F destination (FX-bus 0-63), default 0 + 6 - mono, G destination (FX-bus 0-63), default 0 + 7 - mono, H destination (FX-bus 0-63), default 0 + 8 - left, A destination (FX-bus 0-63), default 0 + 9 - left, B destination (FX-bus 0-63), default 1 + 10 - left, C destination (FX-bus 0-63), default 2 + 11 - left, D destination (FX-bus 0-63), default 3 + 12 - left, E destination (FX-bus 0-63), default 0 + 13 - left, F destination (FX-bus 0-63), default 0 + 14 - left, G destination (FX-bus 0-63), default 0 + 15 - left, H destination (FX-bus 0-63), default 0 + 16 - right, A destination (FX-bus 0-63), default 0 + 17 - right, B destination (FX-bus 0-63), default 1 + 18 - right, C destination (FX-bus 0-63), default 2 + 19 - right, D destination (FX-bus 0-63), default 3 + 20 - right, E destination (FX-bus 0-63), default 0 + 21 - right, F destination (FX-bus 0-63), default 0 + 22 - right, G destination (FX-bus 0-63), default 0 + 23 - right, H destination (FX-bus 0-63), default 0 + +Don't forget that it's illegal to assign a channel to the same FX-bus accumulator +more than once (it means 0=0 && 1=0 is an invalid combination). + +name='EMU10K1 PCM Send Volume',index 0-31 + +It specifies the attenuation (amount) for given destination in range 0-255. +The channel mapping is following: + + 0 - mono, A destination attn, default 255 (no attenuation) + 1 - mono, B destination attn, default 255 (no attenuation) + 2 - mono, C destination attn, default 0 (mute) + 3 - mono, D destination attn, default 0 (mute) + 4 - mono, E destination attn, default 0 (mute) + 5 - mono, F destination attn, default 0 (mute) + 6 - mono, G destination attn, default 0 (mute) + 7 - mono, H destination attn, default 0 (mute) + 8 - left, A destination attn, default 255 (no attenuation) + 9 - left, B destination attn, default 0 (mute) + 10 - left, C destination attn, default 0 (mute) + 11 - left, D destination attn, default 0 (mute) + 12 - left, E destination attn, default 0 (mute) + 13 - left, F destination attn, default 0 (mute) + 14 - left, G destination attn, default 0 (mute) + 15 - left, H destination attn, default 0 (mute) + 16 - right, A destination attn, default 0 (mute) + 17 - right, B destination attn, default 255 (no attenuation) + 18 - right, C destination attn, default 0 (mute) + 19 - right, D destination attn, default 0 (mute) + 20 - right, E destination attn, default 0 (mute) + 21 - right, F destination attn, default 0 (mute) + 22 - right, G destination attn, default 0 (mute) + 23 - right, H destination attn, default 0 (mute) + + + +4) MANUALS/PATENTS: +------------------- + +ftp://opensource.creative.com/pub/doc +------------------------------------- + + Files: + LM4545.pdf AC97 Codec + + m2049.pdf The EMU10K1 Digital Audio Processor + + hog63.ps FX8010 - A DSP Chip Architecture for Audio Effects + + +WIPO Patents +------------ + Patent numbers: + WO 9901813 (A1) Audio Effects Processor with multiple asynchronous (Jan. 14, 1999) + streams + + WO 9901814 (A1) Processor with Instruction Set for Audio Effects (Jan. 14, 1999) + + WO 9901953 (A1) Audio Effects Processor having Decoupled Instruction + Execution and Audio Data Sequencing (Jan. 14, 1999) + + +US Patents (http://www.uspto.gov/) +---------------------------------- + + US 5925841 Digital Sampling Instrument employing cache memory (Jul. 20, 1999) + + US 5928342 Audio Effects Processor integrated on a single chip (Jul. 27, 1999) + with a multiport memory onto which multiple asynchronous + digital sound samples can be concurrently loaded + + US 5930158 Processor with Instruction Set for Audio Effects (Jul. 27, 1999) + + US 6032235 Memory initialization circuit (Tram) (Feb. 29, 2000) + + US 6138207 Interpolation looping of audio samples in cache connected to (Oct. 24, 2000) + system bus with prioritization and modification of bus transfers + in accordance with loop ends and minimum block sizes + + US 6151670 Method for conserving memory storage using a (Nov. 21, 2000) + pool of short term memory registers + + US 6195715 Interrupt control for multiple programs communicating with (Feb. 27, 2001) + a common interrupt by associating programs to GP registers, + defining interrupt register, polling GP registers, and invoking + callback routine associated with defined interrupt register diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 61ae09f49..47a7121b4 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -91,9 +91,12 @@ A regular chown, chgrp and chmod commands (with right permissions) could be used to change the file attributes on hugetlbfs. Also, it is important to note that no such mount command is required if the -applications are going to use only shmat/shmget system calls. It is possible -for same or different applications to use any combination of mmaps and shm* -calls. Though the mount of filesystem will be required for using mmaps. +applications are going to use only shmat/shmget system calls. Users who +wish to use hugetlb page via shared memory segment should be a member of +a supplementary group and system admin needs to configure that gid into +/proc/sys/vm/hugetlb_shm_group. It is possible for same or different +applications to use any combination of mmaps and shm* calls. Though the +mount of filesystem will be required for using mmaps. /* Example of using hugepage in user application using Sys V shared memory * system calls. In this example, app is requesting memory of size 256MB that diff --git a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig index 1def9c72b..6f1dac2e1 100644 --- a/arch/arm/configs/ebsa110_defconfig +++ b/arch/arm/configs/ebsa110_defconfig @@ -2,137 +2,120 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y -# CONFIG_EISA is not set -# CONFIG_SBUS is not set -# CONFIG_MCA is not set +CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_OBSOLETE is not set +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y # # Loadable module support # CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set CONFIG_KMOD=y # # System Type # -# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_ADIFCC is not set # CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set CONFIG_ARCH_EBSA110=y -# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set -# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set # -# Archimedes/A5000 Implementations -# - -# -# Archimedes/A5000 Implementations (select only ONE) -# -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set - -# -# Footbridge Implementations -# -# CONFIG_ARCH_CATS is not set -# CONFIG_ARCH_PERSONAL_SERVER is not set -# CONFIG_ARCH_EBSA285_ADDIN is not set -# CONFIG_ARCH_EBSA285_HOST is not set -# CONFIG_ARCH_NETWINDER is not set - -# -# SA11x0 Implementations -# -# CONFIG_SA1100_ASSABET is not set -# CONFIG_ASSABET_NEPONSET is not set -# CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_CERF is not set -# CONFIG_SA1100_BITSY is not set -# CONFIG_SA1100_EXTENEX1 is not set -# CONFIG_SA1100_FREEBIRD is not set -# CONFIG_SA1100_GRAPHICSCLIENT is not set -# CONFIG_SA1100_JORNADA720 is not set -# CONFIG_SA1100_HUW_WEBPANEL is not set -# CONFIG_SA1100_ITSY is not set -# CONFIG_SA1100_LART is not set -# CONFIG_SA1100_NANOENGINE is not set -# CONFIG_SA1100_OMNIMETER is not set -# CONFIG_SA1100_PANGOLIN is not set -# CONFIG_SA1100_PLEB is not set -# CONFIG_SA1100_SHERMAN is not set -# CONFIG_SA1100_PFS168 is not set -# CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_XP860 is not set -# CONFIG_SA1100_YOPY is not set - -# -# CLPS711X/EP721X Implementations +# Processor Type # -# CONFIG_ARCH_P720T is not set -# CONFIG_ARCH_ACORN is not set -# CONFIG_FOOTBRIDGE is not set -# CONFIG_FOOTBRIDGE_HOST is not set -# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set +CONFIG_CPU_SA110=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_V4WB=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WB=y # -# Processor Type +# Processor Features # -# CONFIG_CPU_32v3 is not set -CONFIG_CPU_32v4=y -# CONFIG_CPU_ARM610 is not set -# CONFIG_CPU_ARM710 is not set -# CONFIG_CPU_ARM720T is not set -# CONFIG_CPU_ARM920T is not set -# CONFIG_CPU_ARM1020 is not set -CONFIG_CPU_SA110=y -# CONFIG_CPU_SA1100 is not set -# CONFIG_DISCONTIGMEM is not set # # General setup # -# CONFIG_PCI is not set CONFIG_ISA=y -# CONFIG_ISA_DMA is not set -CONFIG_HOTPLUG=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 # # PCMCIA/CardBus support # CONFIG_PCMCIA=m -CONFIG_I82365=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_I82365=m # CONFIG_TCIC is not set -# CONFIG_PCMCIA_CLPS6700 is not set -# CONFIG_PCMCIA_SA1100 is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y +CONFIG_PCMCIA_PROBE=y + +# +# At least one math emulation must be selected +# CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set CONFIG_FPE_FASTFPE=y -CONFIG_KCORE_ELF=y -# CONFIG_KCORE_AOUT is not set -CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y # CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set # CONFIG_PM is not set +# CONFIG_PREEMPT is not set # CONFIG_ARTHUR is not set CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" CONFIG_LEDS=y @@ -143,22 +126,18 @@ CONFIG_LEDS_TIMER=y # CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_CML1=y CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_PC_SUPERIO is not set # CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_ARC is not set -# CONFIG_PARPORT_AMIGA is not set -# CONFIG_PARPORT_MFC3 is not set -# CONFIG_PARPORT_ATARI is not set -# CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set CONFIG_PARPORT_1284=y # -# Plug and Play configuration +# Plug and Play support # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # Block devices @@ -166,9 +145,6 @@ CONFIG_PARPORT_1284=y # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y @@ -179,37 +155,29 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # Multi-device support (RAID and LVM) # # CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_LVM is not set + +# +# Networking support +# +CONFIG_NET=y # # Networking options # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y # CONFIG_NETLINK_DEV is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -# CONFIG_FILTER is not set CONFIG_UNIX=y +# CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_FWMARK=y CONFIG_IP_ROUTE_NAT=y # CONFIG_IP_ROUTE_MULTIPATH is not set # CONFIG_IP_ROUTE_TOS is not set CONFIG_IP_ROUTE_VERBOSE=y -# CONFIG_IP_ROUTE_LARGE_TABLES is not set CONFIG_IP_PNP=y # CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y @@ -218,64 +186,113 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -CONFIG_INET_ECN=y CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_TUNNEL is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set # -# IP: Netfilter Configuration +# IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=y CONFIG_IP_NF_FTP=y CONFIG_IP_NF_IRC=y +# CONFIG_IP_NF_TFTP is not set +# CONFIG_IP_NF_AMANDA is not set # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=y -# CONFIG_IP_NF_MATCH_MAC is not set +CONFIG_IP_NF_MATCH_IPRANGE=y +CONFIG_IP_NF_MATCH_MAC=y +CONFIG_IP_NF_MATCH_PKTTYPE=y CONFIG_IP_NF_MATCH_MARK=y CONFIG_IP_NF_MATCH_MULTIPORT=y CONFIG_IP_NF_MATCH_TOS=y -# CONFIG_IP_NF_MATCH_TCPMSS is not set +CONFIG_IP_NF_MATCH_RECENT=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_DSCP=y +CONFIG_IP_NF_MATCH_AH_ESP=y +CONFIG_IP_NF_MATCH_LENGTH=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_MATCH_TCPMSS=y +CONFIG_IP_NF_MATCH_HELPER=y CONFIG_IP_NF_MATCH_STATE=y -CONFIG_IP_NF_MATCH_UNCLEAN=y +CONFIG_IP_NF_MATCH_CONNTRACK=y # CONFIG_IP_NF_MATCH_OWNER is not set CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y -# CONFIG_IP_NF_TARGET_MIRROR is not set CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_SAME=y +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set CONFIG_IP_NF_NAT_IRC=y CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_TOS=y +CONFIG_IP_NF_TARGET_ECN=y +CONFIG_IP_NF_TARGET_DSCP=y CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_CLASSIFY=y CONFIG_IP_NF_TARGET_LOG=y -# CONFIG_IP_NF_TARGET_TCPMSS is not set -CONFIG_IPV6=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=y +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_RAW is not set # -# IPv6: Netfilter Configuration +# IPv6: Netfilter Configuration # +# CONFIG_IP6_NF_QUEUE is not set CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_LIMIT=y +CONFIG_IP6_NF_MATCH_MAC=y +CONFIG_IP6_NF_MATCH_RT=y +CONFIG_IP6_NF_MATCH_OPTS=y +CONFIG_IP6_NF_MATCH_FRAG=y +CONFIG_IP6_NF_MATCH_HL=y +CONFIG_IP6_NF_MATCH_MULTIPORT=y +# CONFIG_IP6_NF_MATCH_OWNER is not set CONFIG_IP6_NF_MATCH_MARK=y +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +CONFIG_IP6_NF_MATCH_AHESP=y +CONFIG_IP6_NF_MATCH_LENGTH=y +# CONFIG_IP6_NF_MATCH_EUI64 is not set CONFIG_IP6_NF_FILTER=y +# CONFIG_IP6_NF_TARGET_LOG is not set CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_TARGET_MARK=y -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set +# CONFIG_IP6_NF_RAW is not set # -# +# SCTP Configuration (EXPERIMENTAL) # +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_LLC is not set # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -288,25 +305,30 @@ CONFIG_IP6_NF_TARGET_MARK=y # CONFIG_NET_SCHED is not set # -# Network device support +# Network testing # +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # ARCnet devices # # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set CONFIG_ARM_AM79C961A=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -322,40 +344,20 @@ CONFIG_ARM_AM79C961A=y # # Ethernet (1000 Mbit) # -# CONFIG_ACENIC is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=m -# CONFIG_PPP_SYNC_TTY is not set -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -# CONFIG_PPPOE is not set -# CONFIG_SLIP is not set # -# Wireless LAN (non-hamradio) +# Ethernet (10000 Mbit) # -# CONFIG_NET_RADIO is not set # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set # -# Wan interfaces +# Wireless LAN (non-hamradio) # -# CONFIG_WAN is not set +# CONFIG_NET_RADIO is not set # # PCMCIA network device support @@ -368,39 +370,42 @@ CONFIG_PCMCIA_PCNET=m # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set -# CONFIG_ARCNET_COM20020_CS is not set -# CONFIG_PCMCIA_IBMTR is not set -# CONFIG_NET_PCMCIA_RADIO is not set +# CONFIG_PCMCIA_AXNET is not set # -# Amateur Radio support +# Wan interfaces # -# CONFIG_HAMRADIO is not set +# CONFIG_WAN is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # -# IrDA (infrared) support +# SCSI device support # -# CONFIG_IRDA is not set +# CONFIG_SCSI is not set # -# ATA/IDE/MFM/RLL support +# Fusion MPT device support # -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_HD is not set # -# SCSI support +# IEEE 1394 (FireWire) support # -# CONFIG_SCSI is not set +# CONFIG_IEEE1394 is not set # # I2O device support # -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set # # ISDN subsystem @@ -408,76 +413,80 @@ CONFIG_PCMCIA_PCNET=m # CONFIG_ISDN is not set # -# Input core support +# Input device support # # CONFIG_INPUT is not set # -# Character devices +# Userland interfaces # -# CONFIG_VT is not set -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -CONFIG_SERIAL_EXTENDED=y -# CONFIG_SERIAL_MANY_PORTS is not set -# CONFIG_SERIAL_SHARE_IRQ is not set -# CONFIG_SERIAL_DETECT_IRQ is not set -# CONFIG_SERIAL_MULTIPORT is not set -# CONFIG_HUB6 is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_SERIAL_21285 is not set -# CONFIG_SERIAL_21285_OLD is not set -# CONFIG_SERIAL_21285_CONSOLE is not set -# CONFIG_SERIAL_SA1100 is not set -# CONFIG_SERIAL_SA1100_CONSOLE is not set -# CONFIG_SERIAL_AMBA is not set -# CONFIG_SERIAL_AMBA_CONSOLE is not set -# CONFIG_SERIAL_CLPS711X is not set -# CONFIG_SERIAL_CLPS711X_CONSOLE is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set # -# I2C support +# Input I/O drivers # -# CONFIG_I2C is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set # -# Mice +# Input Device Drivers # -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set # -# Joysticks +# Character devices # -# CONFIG_JOYSTICK is not set +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set # -# Input core support is needed for joysticks +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + # +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set # CONFIG_QIC02_TAPE is not set +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + # # Watchdog Cards # CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# CONFIG_SOFT_WATCHDOG=y -# CONFIG_WDT is not set -# CONFIG_WDTPCI is not set + +# +# ISA-based Watchdog Cards +# # CONFIG_PCWATCHDOG is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_ADVANTECH_WDT is not set -# CONFIG_60XX_WDT is not set # CONFIG_MIXCOMWD is not set -# CONFIG_MACHZ_WDT is not set -# CONFIG_INTEL_RNG is not set +# CONFIG_WDT is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -492,81 +501,97 @@ CONFIG_SOFT_WATCHDOG=y # # PCMCIA character devices # -# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + # # File systems # +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# # CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -CONFIG_MINIX_FS=y # CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_DEBUG is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # -# CONFIG_CODA_FS is not set CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -CONFIG_ROOT_NFS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set -CONFIG_SUNRPC=y +CONFIG_ROOT_NFS=y CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set # CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set # # Partition Types @@ -578,26 +603,68 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set -# CONFIG_SMB_NLS is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# # CONFIG_NLS is not set +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + # # USB support # -# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set # # Kernel hacking # CONFIG_FRAME_POINTER=y -CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set -CONFIG_MAGIC_SYSRQ=y -# CONFIG_NO_PGT_CACHE is not set -# CONFIG_DEBUG_LL is not set -# CONFIG_DEBUG_DC21285_PORT is not set -# CONFIG_DEBUG_CLPS711X_UART2 is not set +# CONFIG_DEBUG_KERNEL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig new file mode 100644 index 000000000..fd95f39bc --- /dev/null +++ b/arch/arm/configs/ixp4xx_defconfig @@ -0,0 +1,1081 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +CONFIG_ARCH_IXP4XX=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y + +# +# Intel IXP4xx Implementation Options +# + +# +# IXP4xx Platforms +# +CONFIG_ARCH_IXDP425=y +CONFIG_ARCH_IXCDP1100=y +CONFIG_ARCH_PRPMC1100=y +CONFIG_ARCH_ADI_COYOTE=y +# CONFIG_ARCH_AVILA is not set +CONFIG_ARCH_IXDP4XX=y + +# +# IXP4xx Options +# +# CONFIG_IXP4XX_INDIRECT_PCI is not set + +# +# Intel PXA250/210 Implementations +# + +# +# SA11x0 Implementations +# + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# + +# +# OMAP Board Type +# + +# +# OMAP Feature Selections +# + +# +# S3C2410 Implementations +# + +# +# LH7A40X Implementations +# +CONFIG_DMABOUNCE=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_CPU_BIG_ENDIAN=y +CONFIG_XSCALE_PMU=y + +# +# General setup +# +CONFIG_PCI=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +# CONFIG_PREEMPT is not set +CONFIG_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_IXP4XX=y +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_CARMEL is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=m +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +CONFIG_IP_VS_DEBUG=y +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +# CONFIG_IP_VS_PROTO_TCP is not set +# CONFIG_IP_VS_PROTO_UDP is not set +# CONFIG_IP_VS_PROTO_ESP is not set +# CONFIG_IP_VS_PROTO_AH is not set + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS application helper +# +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_TFTP is not set +# CONFIG_IP_NF_AMANDA is not set +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +# CONFIG_IP_NF_MATCH_IPRANGE is not set +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +CONFIG_IP_NF_MATCH_OWNER=m +# CONFIG_IP_NF_MATCH_PHYSDEV is not set +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +# CONFIG_IP_NF_TARGET_CLASSIFY is not set +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +# CONFIG_IP_NF_ARP_MANGLE is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_COMPAT_IPFWADM=m +# CONFIG_IP_NF_RAW is not set + +# +# Bridge: Netfilter Configuration +# +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +# CONFIG_NET_DIVERT is not set +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_CSZ=m +# CONFIG_NET_SCH_ATM is not set +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +# CONFIG_NET_SCH_DELAY is not set +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +# CONFIG_AIRO is not set +CONFIG_HERMES=y +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +CONFIG_PCI_HERMES=y +# CONFIG_ATMEL is not set + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_NET_WIRELESS=y + +# +# Wan interfaces +# +CONFIG_WAN=y +# CONFIG_DSCC4 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_SYNCLINK_SYNCPPP is not set +CONFIG_HDLC=m +CONFIG_HDLC_RAW=y +# CONFIG_HDLC_RAW_ETH is not set +CONFIG_HDLC_CISCO=y +CONFIG_HDLC_FR=y +CONFIG_HDLC_PPP=y +CONFIG_HDLC_X25=y +# CONFIG_PCI200SYN is not set +# CONFIG_WANXL is not set +# CONFIG_PC300 is not set +# CONFIG_FARSYNC is not set +CONFIG_DLCI=m +CONFIG_DLCI_COUNT=24 +CONFIG_DLCI_MAX=8 +CONFIG_WAN_ROUTER_DRIVERS=y +# CONFIG_CYCLADES_SYNC is not set +# CONFIG_LAPBETHER is not set +# CONFIG_X25_ASY is not set + +# +# ATM drivers +# +CONFIG_ATM_TCP=m +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_FORE200E_MAYBE is not set +# CONFIG_ATM_HE is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_IXP4XX_WATCHDOG=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_ISA is not set +CONFIG_I2C_IXP4XX=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_BDI2000_XSCALE is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/configs/lpd7a400_defconfig b/arch/arm/configs/lpd7a400_defconfig index 2fd8da9f1..7bbb7181d 100644 --- a/arch/arm/configs/lpd7a400_defconfig +++ b/arch/arm/configs/lpd7a400_defconfig @@ -19,19 +19,23 @@ CONFIG_BROKEN_ON_SMP=y # # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set CONFIG_FUTEX=y # CONFIG_EPOLL is not set CONFIG_IOSCHED_NOOP=y # CONFIG_IOSCHED_AS is not set # CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y # @@ -43,21 +47,24 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y # System Type # # CONFIG_ARCH_ADIFCC is not set -# CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set -# CONFIG_ARCH_PXA is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_SHARK is not set CONFIG_ARCH_LH7A40X=y +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set # # CLPS711X/EP721X Implementations @@ -82,13 +89,45 @@ CONFIG_ARCH_LH7A40X=y # # -# Intel PXA250/210 Implementations +# Intel IXP4xx Implementation Options +# + +# +# IXP4xx Platforms +# + +# +# IXP4xx Options +# + +# +# Intel PXA2xx Implementations # # # SA11x0 Implementations # +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# + +# +# OMAP Board Type +# + +# +# OMAP Feature Selections +# + +# +# S3C2410 Implementations +# + # # LH7A40X Implementations # @@ -254,23 +293,21 @@ CONFIG_IP_PNP_RARP=y # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_NETFILTER is not set # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -291,6 +328,11 @@ CONFIG_IPV6_SCTP__=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -311,38 +353,24 @@ CONFIG_SMC91X=y # # Ethernet (10000 Mbit) # -# CONFIG_PPP is not set -# CONFIG_SLIP is not set # -# Wireless LAN (non-hamradio) +# Token Ring devices # -# CONFIG_NET_RADIO is not set # -# Token Ring devices +# Wireless LAN (non-hamradio) # -# CONFIG_SHAPER is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ATA/ATAPI/MFM/RLL support @@ -367,9 +395,9 @@ CONFIG_IDE_POLL=y # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y +CONFIG_IDE_ARM=y # CONFIG_BLK_DEV_IDEDMA is not set # CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_HD is not set # @@ -452,11 +480,6 @@ CONFIG_SERIAL_LH7A40X_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# Mice -# -# CONFIG_BUSMOUSE is not set # CONFIG_QIC02_TAPE is not set # @@ -536,6 +559,7 @@ CONFIG_VFAT_FS=y # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -576,7 +600,7 @@ CONFIG_LOCKD=y CONFIG_LOCKD_V4=y # CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -664,6 +688,11 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y +# +# Sound +# +# CONFIG_SOUND is not set + # # Misc devices # @@ -706,5 +735,6 @@ CONFIG_DEBUG_ERRORS=y # Library routines # CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/configs/lpd7a404_defconfig b/arch/arm/configs/lpd7a404_defconfig index a13b52210..517f486d9 100644 --- a/arch/arm/configs/lpd7a404_defconfig +++ b/arch/arm/configs/lpd7a404_defconfig @@ -19,19 +19,23 @@ CONFIG_BROKEN_ON_SMP=y # # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set CONFIG_FUTEX=y # CONFIG_EPOLL is not set CONFIG_IOSCHED_NOOP=y # CONFIG_IOSCHED_AS is not set # CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y # @@ -46,19 +50,21 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set -# CONFIG_ARCH_PXA is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set -# CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_S3C2410 is not set -# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_SHARK is not set CONFIG_ARCH_LH7A40X=y +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set # # CLPS711X/EP721X Implementations @@ -83,7 +89,19 @@ CONFIG_ARCH_LH7A40X=y # # -# Intel PXA250/210 Implementations +# Intel IXP4xx Implementation Options +# + +# +# IXP4xx Platforms +# + +# +# IXP4xx Options +# + +# +# Intel PXA2xx Implementations # # @@ -94,6 +112,14 @@ CONFIG_ARCH_LH7A40X=y # TI OMAP Implementations # +# +# OMAP Core Type +# + +# +# OMAP Board Type +# + # # OMAP Feature Selections # @@ -271,8 +297,6 @@ CONFIG_IP_PNP_RARP=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_NETFILTER is not set # @@ -280,7 +304,9 @@ CONFIG_IP_PNP_RARP=y # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -301,6 +327,11 @@ CONFIG_IP_PNP_RARP=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -321,41 +352,24 @@ CONFIG_SMC91X=y # # Ethernet (10000 Mbit) # -# CONFIG_PPP is not set -# CONFIG_SLIP is not set # -# Wireless LAN (non-hamradio) +# Token Ring devices # -# CONFIG_NET_RADIO is not set # -# Token Ring devices +# Wireless LAN (non-hamradio) # -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ATA/ATAPI/MFM/RLL support @@ -381,6 +395,7 @@ CONFIG_IDE_POLL=y # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y +CONFIG_IDE_ARM=y # CONFIG_BLK_DEV_IDEDMA is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_HD is not set @@ -404,7 +419,6 @@ CONFIG_SCSI=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set @@ -418,6 +432,7 @@ CONFIG_SCSI=y # SCSI low-level drivers # # CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_DEBUG is not set @@ -573,6 +588,7 @@ CONFIG_VFAT_FS=y # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -618,7 +634,6 @@ CONFIG_SUNRPC=y # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -761,6 +776,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -809,6 +825,8 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -845,5 +863,6 @@ CONFIG_DEBUG_ERRORS=y # Library routines # CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig new file mode 100644 index 000000000..925b2777f --- /dev/null +++ b/arch/arm/configs/mainstone_defconfig @@ -0,0 +1,743 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +CONFIG_ARCH_PXA=y +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# + +# +# Intel PXA2xx Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +CONFIG_MACH_MAINSTONE=y +# CONFIG_ARCH_PXA_IDP is not set +CONFIG_PXA27x=y +CONFIG_IWMMXT=y + +# +# SA11x0 Implementations +# + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# + +# +# OMAP Board Type +# + +# +# OMAP Feature Selections +# + +# +# S3C2410 Implementations +# + +# +# LH7A40X Implementations +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_XSCALE_PMU=y + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_PXA2XX=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +# CONFIG_MTD_CFI_B2 is not set +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +# CONFIG_MTD_CFI_I1 is not set +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/configs/smdk2410_defconfig b/arch/arm/configs/smdk2410_defconfig new file mode 100644 index 000000000..a88724f26 --- /dev/null +++ b/arch/arm/configs/smdk2410_defconfig @@ -0,0 +1,667 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +CONFIG_ARCH_S3C2410=y +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# + +# +# Intel PXA250/210 Implementations +# + +# +# SA11x0 Implementations +# + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# + +# +# OMAP Board Type +# + +# +# OMAP Feature Selections +# + +# +# S3C2410 Implementations +# +# CONFIG_ARCH_BAST is not set +# CONFIG_ARCH_H1940 is not set +CONFIG_ARCH_SMDK2410=y +# CONFIG_MACH_VR1000 is not set + +# +# LH7A40X Implementations +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM920T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 + +# +# At least one math emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=1f04 mem=32M" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_CONCAT is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_S3C2410=y +CONFIG_SERIAL_S3C2410_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set +CONFIG_DEBUG_LL_PRINTK=y +CONFIG_DEBUG_S3C2410_PORT=y +CONFIG_DEBUG_S3C2410_UART=0 + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index b419d0b5f..007a5a012 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -24,7 +24,6 @@ lib-$(CONFIG_ARCH_RPC) += ecard.o io-acorn.o floppydma.o lib-$(CONFIG_ARCH_CLPS7500) += io-acorn.o lib-$(CONFIG_ARCH_L7200) += io-acorn.o lib-$(CONFIG_ARCH_SHARK) += io-shark.o -lib-$(CONFIG_ARCH_CLPS711X) += io-acorn.o $(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S index 99378ecd7..3aacd01d4 100644 --- a/arch/arm/lib/io-acorn.S +++ b/arch/arm/lib/io-acorn.S @@ -17,31 +17,6 @@ .text .align - .equ diff_pcio_base, PCIO_BASE - IO_BASE - - .macro outw2 rd - mov r8, \rd, lsl #16 - orr r8, r8, r8, lsr #16 - str r8, [r3, r0, lsl #2] - mov r8, \rd, lsr #16 - orr r8, r8, r8, lsl #16 - str r8, [r3, r0, lsl #2] - .endm - - .macro inw2 rd, mask, temp - ldr \rd, [r0] - and \rd, \rd, \mask - ldr \temp, [r0] - orr \rd, \rd, \temp, lsl #16 - .endm - - .macro addr rd - tst \rd, #0x80000000 - mov \rd, \rd, lsl #2 - add \rd, \rd, #IO_BASE - addeq \rd, \rd, #diff_pcio_base - .endm - .iosl_warning: .ascii "<4>insl/outsl not implemented, called from %08lX\0" .align diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig index 4e2278f95..f6e676322 100644 --- a/arch/arm/mach-clps711x/Kconfig +++ b/arch/arm/mach-clps711x/Kconfig @@ -1,16 +1,15 @@ +if ARCH_CLPS711X menu "CLPS711X/EP721X Implementations" config ARCH_AUTCPU12 bool "AUTCPU12" - depends on ARCH_CLPS711X help Say Y if you intend to run the kernel on the autronix autcpu12 board. This board is based on a Cirrus Logic CS89712. config ARCH_CDB89712 bool "CDB89712" - depends on ARCH_CLPS711X help This is an evaluation board from Cirrus for the CS89712 processor. The board includes 2 serial ports, Ethernet, IRDA, and expansion @@ -18,32 +17,27 @@ config ARCH_CDB89712 config ARCH_CEIVA bool "CEIVA" - depends on ARCH_CLPS711X help Say Y here if you intend to run this kernel on the Ceiva/Polaroid PhotoMax Digital Picture Frame. config ARCH_CLEP7312 bool "CLEP7312" - depends on ARCH_CLPS711X config ARCH_EDB7211 bool "EDB7211" - depends on ARCH_CLPS711X help Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211 evaluation board. config ARCH_P720T bool "P720T" - depends on ARCH_CLPS711X help Say Y here if you intend to run this kernel on the ARM Prospector 720T. config ARCH_FORTUNET bool "FORTUNET" - depends on ARCH_CLPS711X # XXX Maybe these should indicate register compatibility # instead of being mutually exclusive. @@ -74,3 +68,4 @@ config EP72XX_ROM_BOOT endmenu +endif diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c index c948ddf30..6556818e4 100644 --- a/arch/arm/mach-ebsa110/io.c +++ b/arch/arm/mach-ebsa110/io.c @@ -67,9 +67,9 @@ u8 __readb(void *addr) u32 ret, a = __isamem_convert_addr(addr); if ((int)addr & 1) - ret = __raw_getl(a); + ret = __raw_readl(a); else - ret = __raw_getb(a); + ret = __raw_readb(a); return ret; } @@ -80,7 +80,7 @@ u16 __readw(void *addr) if ((int)addr & 1) BUG(); - return __raw_getw(a); + return __raw_readw(a); } u32 __readl(void *addr) @@ -90,8 +90,8 @@ u32 __readl(void *addr) if ((int)addr & 3) BUG(); - ret = __raw_getw(a); - ret |= __raw_getw(a + 4) << 16; + ret = __raw_readw(a); + ret |= __raw_readw(a + 4) << 16; return ret; } @@ -104,9 +104,9 @@ void __writeb(u8 val, void *addr) u32 a = __isamem_convert_addr(addr); if ((int)addr & 1) - __raw_putl(val, a); + __raw_writel(val, a); else - __raw_putb(val, a); + __raw_writeb(val, a); } void __writew(u16 val, void *addr) @@ -116,7 +116,7 @@ void __writew(u16 val, void *addr) if ((int)addr & 1) BUG(); - __raw_putw(val, a); + __raw_writew(val, a); } void __writel(u32 val, void *addr) @@ -126,8 +126,8 @@ void __writel(u32 val, void *addr) if ((int)addr & 3) BUG(); - __raw_putw(val, a); - __raw_putw(val >> 16, a + 4); + __raw_writew(val, a); + __raw_writew(val >> 16, a + 4); } EXPORT_SYMBOL(__writeb); @@ -147,7 +147,7 @@ u8 __inb(int port) * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - ret = __raw_getb(ISAIO_BASE + (port << 2)); + ret = __raw_readb(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -155,9 +155,9 @@ u8 __inb(int port) * Shame nothing else does */ if (port & 1) - ret = __raw_getl(a); + ret = __raw_readl(a); else - ret = __raw_getb(a); + ret = __raw_readb(a); } return ret; } @@ -170,7 +170,7 @@ u16 __inw(int port) * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - ret = __raw_getw(ISAIO_BASE + (port << 2)); + ret = __raw_readw(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -180,7 +180,7 @@ u16 __inw(int port) if (port & 1) BUG(); - ret = __raw_getw(a); + ret = __raw_readw(a); } return ret; } @@ -201,7 +201,7 @@ void __outb(u8 val, int port) * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - __raw_putb(val, ISAIO_BASE + (port << 2)); + __raw_writeb(val, ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -209,9 +209,9 @@ void __outb(u8 val, int port) * Shame nothing else does */ if (port & 1) - __raw_putl(val, a); + __raw_writel(val, a); else - __raw_putb(val, a); + __raw_writeb(val, a); } } @@ -230,7 +230,7 @@ void __outw(u16 val, int port) BUG(); } - __raw_putw(val, ISAIO_BASE + off); + __raw_writew(val, ISAIO_BASE + off); } void __outl(u32 val, int port) diff --git a/arch/arm/mach-epxa10db/Kconfig b/arch/arm/mach-epxa10db/Kconfig index e88d914ef..55d896dd4 100644 --- a/arch/arm/mach-epxa10db/Kconfig +++ b/arch/arm/mach-epxa10db/Kconfig @@ -1,17 +1,16 @@ +if ARCH_CAMELOT menu "Epxa10db" comment "PLD hotswap support" - depends on ARCH_CAMELOT config PLD bool - depends on ARCH_CAMELOT default y config PLD_HOTSWAP bool "Support for PLD device hotplugging (experimental)" - depends on ARCH_CAMELOT && EXPERIMENTAL + depends on EXPERIMENTAL help This enables support for the dynamic loading and configuration of compatible drivers when the contents of the PLD are changed. This @@ -21,3 +20,4 @@ config PLD_HOTSWAP endmenu +endif diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig index 510f896fd..1eaea0b87 100644 --- a/arch/arm/mach-footbridge/Kconfig +++ b/arch/arm/mach-footbridge/Kconfig @@ -1,9 +1,9 @@ +if ARCH_FOOTBRIDGE menu "Footbridge Implementations" config ARCH_CATS bool "CATS" - depends on ARCH_FOOTBRIDGE help Say Y here if you intend to run this kernel on the CATS. @@ -11,7 +11,6 @@ config ARCH_CATS config ARCH_PERSONAL_SERVER bool "Compaq Personal Server" - depends on ARCH_FOOTBRIDGE ---help--- Say Y here if you intend to run this kernel on the Compaq Personal Server. @@ -29,7 +28,6 @@ config ARCH_PERSONAL_SERVER config ARCH_EBSA285_ADDIN bool "EBSA285 (addin mode)" - depends on ARCH_FOOTBRIDGE help Say Y here if you intend to run this kernel on the EBSA285 card in addin mode. @@ -38,7 +36,6 @@ config ARCH_EBSA285_ADDIN config ARCH_EBSA285_HOST bool "EBSA285 (host mode)" - depends on ARCH_FOOTBRIDGE help Say Y here if you intend to run this kernel on the EBSA285 card in host ("central function") mode. @@ -47,7 +44,6 @@ config ARCH_EBSA285_HOST config ARCH_NETWINDER bool "NetWinder" - depends on ARCH_FOOTBRIDGE help Say Y here if you intend to run this kernel on the Rebel.COM NetWinder. Information about this machine can be found at: @@ -58,3 +54,4 @@ config ARCH_NETWINDER endmenu +endif diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index 47f67a206..df97d1639 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -1,5 +1,6 @@ +if ARCH_INTEGRATOR + menu "Integrator Options" - depends on ARCH_INTEGRATOR config ARCH_INTEGRATOR_AP bool "Support Integrator/AP and Integrator/PP2 platforms" @@ -28,3 +29,5 @@ config INTEGRATOR_IMPD1 module will be called impd1. endmenu + +endif diff --git a/arch/arm/mach-iop3xx/Kconfig b/arch/arm/mach-iop3xx/Kconfig index a253ad4dc..6a388e273 100644 --- a/arch/arm/mach-iop3xx/Kconfig +++ b/arch/arm/mach-iop3xx/Kconfig @@ -1,10 +1,10 @@ +if ARCH_IOP3XX menu "IOP3xx Implementation Options" choice prompt "IOP3xx System Type" default ARCH_IQ80310 - depends on ARCH_IOP3XX config ARCH_IQ80310 bool "IQ80310" @@ -36,19 +36,20 @@ comment "IOP3xx Chipset Features" config IOP3XX_AAU bool "Support Intel IOP3xx Application Accelerator Unit (EXPERIMENTAL)" - depends on ARCH_IOP3XX && EXPERIMENTAL + depends on EXPERIMENTAL config IOP3XX_DMA bool "Support Intel IOP3xx DMA (EXPERIMENTAL)" - depends on ARCH_IOP3XX && EXPERIMENTAL + depends on EXPERIMENTAL config IOP3XX_MU bool "Support Intel IOP3xx Messaging Unit (EXPERIMENTAL)" - depends on ARCH_IOP3XX && EXPERIMENTAL + depends on EXPERIMENTAL config IOP3XX_PMON bool "Support Intel IOP3xx Performance Monitor (EXPERIMENTAL)" - depends on ARCH_IOP3XX && EXPERIMENTAL + depends on EXPERIMENTAL endmenu +endif diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 3377f887b..46b72e106 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -1,7 +1,7 @@ +if ARCH_IXP4XX config ARCH_SUPPORTS_BIG_ENDIAN bool - depends on ARCH_IXP4XX default y menu "Intel IXP4xx Implementation Options" @@ -10,7 +10,6 @@ comment "IXP4xx Platforms" config ARCH_AVILA bool "Avila" - depends on ARCH_IXP4XX help Say 'Y' here if you want your kernel to support the Gateworks Avila Network Platform. For more information on this platform, @@ -18,7 +17,6 @@ config ARCH_AVILA config ARCH_ADI_COYOTE bool "Coyote" - depends on ARCH_IXP4XX help Say 'Y' here if you want your kernel to support the ADI Engineering Coyote Gateway Reference Platform. For more @@ -26,7 +24,6 @@ config ARCH_ADI_COYOTE config ARCH_IXDP425 bool "IXDP425" - depends on ARCH_IXP4XX help Say 'Y' here if you want your kernel to support Intel's IXDP425 Development Platform (Also known as Richfield). @@ -44,7 +41,6 @@ config ARCH_IXCDP1100 config ARCH_PRPMC1100 bool "PrPMC1100" - depends on ARCH_IXP4XX help Say 'Y' here if you want your kernel to support the Motorola PrPCM1100 Processor Mezanine Module. For more information on @@ -62,7 +58,6 @@ comment "IXP4xx Options" config IXP4XX_INDIRECT_PCI bool "Use indirect PCI memory access" - depends on ARCH_IXP4XX help IXP4xx provides two methods of accessing PCI memory space: @@ -87,3 +82,5 @@ config IXP4XX_INDIRECT_PCI what you need, leave this option unselected. endmenu + +endif diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile new file mode 100644 index 000000000..f656397f8 --- /dev/null +++ b/arch/arm/mach-ixp4xx/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# + +obj-y += common.o common-pci.o + +obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o ixdp425-setup.o +obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o +obj-$(CONFIG_ARCH_PRPMC1100) += prpmc1100-pci.o prpmc1100-setup.o + diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c new file mode 100644 index 000000000..c20dc3226 --- /dev/null +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -0,0 +1,543 @@ +/* + * arch/arm/mach-ixp4xx/common-pci.c + * + * IXP4XX PCI routines for all platforms + * + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003 Greg Ungerer + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* + * IXP4xx PCI read function is dependent on whether we are + * running A0 or B0 (AppleGate) silicon. + */ +int (*ixp4xx_pci_read)(u32 addr, u32 cmd, u32* data); + +/* + * Base address for PCI regsiter region + */ +unsigned long ixp4xx_pci_reg_base = 0; + +/* + * PCI cfg an I/O routines are done by programming a + * command/byte enable register, and then read/writing + * the data from a data regsiter. We need to ensure + * these transactions are atomic or we will end up + * with corrupt data on the bus or in a driver. + */ +static spinlock_t ixp4xx_pci_lock = SPIN_LOCK_UNLOCKED; + +/* + * Read from PCI config space + */ +static void crp_read(u32 ad_cbe, u32 *data) +{ + unsigned long flags; + spin_lock_irqsave(&ixp4xx_pci_lock, flags); + *PCI_CRP_AD_CBE = ad_cbe; + *data = *PCI_CRP_RDATA; + spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); +} + +/* + * Write to PCI config space + */ +static void crp_write(u32 ad_cbe, u32 data) +{ + unsigned long flags; + spin_lock_irqsave(&ixp4xx_pci_lock, flags); + *PCI_CRP_AD_CBE = CRP_AD_CBE_WRITE | ad_cbe; + *PCI_CRP_WDATA = data; + spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); +} + +static inline int check_master_abort(void) +{ + /* check Master Abort bit after access */ + unsigned long isr = *PCI_ISR; + + if (isr & PCI_ISR_PFE) { + /* make sure the Master Abort bit is reset */ + *PCI_ISR = PCI_ISR_PFE; + pr_debug("%s failed\n", __FUNCTION__); + return 1; + } + + return 0; +} + +int ixp4xx_pci_read_errata(u32 addr, u32 cmd, u32* data) +{ + unsigned long flags; + int retval = 0; + int i; + + spin_lock_irqsave(&ixp4xx_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* + * PCI workaround - only works if NP PCI space reads have + * no side effects!!! Read 8 times. last one will be good. + */ + for (i = 0; i < 8; i++) { + *PCI_NP_CBE = cmd; + *data = *PCI_NP_RDATA; + *data = *PCI_NP_RDATA; + } + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); + return retval; +} + +int ixp4xx_pci_read_no_errata(u32 addr, u32 cmd, u32* data) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&ixp4xx_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* set up and execute the read */ + *PCI_NP_CBE = cmd; + + /* the result of the read is now in NP_RDATA */ + *data = *PCI_NP_RDATA; + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); + return retval; +} + +int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&ixp4xx_pci_lock, flags); + + *PCI_NP_AD = addr; + + /* set up the write */ + *PCI_NP_CBE = cmd; + + /* execute the write by writing to NP_WDATA */ + *PCI_NP_WDATA = data; + + if(check_master_abort()) + retval = 1; + + spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); + return retval; +} + +static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where) +{ + u32 addr; + if (!bus_num) { + /* type 0 */ + addr = BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | + (where & ~3); + } else { + /* type 1 */ + addr = (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | + ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; + } + return addr; +} + +/* + * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes. + * 0 and 3 are not valid indexes... + */ +static u32 bytemask[] = { + /*0*/ 0, + /*1*/ 0xff, + /*2*/ 0xffff, + /*3*/ 0, + /*4*/ 0xffffffff, +}; + +static u32 local_byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int local_read_config(int where, int size, u32 *value) +{ + u32 n, data; + pr_debug("local_read_config from %d size %d\n", where, size); + n = where % 4; + crp_read(where & ~3, &data); + *value = (data >> (8*n)) & bytemask[size]; + pr_debug("local_read_config read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int local_write_config(int where, int size, u32 value) +{ + u32 n, byte_enables, data; + pr_debug("local_write_config %#x to %d size %d\n", value, where, size); + n = where % 4; + byte_enables = local_byte_lane_enable_bits(n, size); + if (byte_enables == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + data = value << (8*n); + crp_write((where & ~3) | byte_enables, data); + return PCIBIOS_SUCCESSFUL; +} + +static u32 byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << 4; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << 4; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int read_config(u8 bus_num, u16 devfn, int where, int size, u32 *value) +{ + u32 n, byte_enables, addr, data; + + pr_debug("read_config from %d size %d dev %d:%d:%d\n", where, size, + bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + *value = 0xffffffff; + n = where % 4; + byte_enables = byte_lane_enable_bits(n, size); + if (byte_enables == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + if (ixp4xx_pci_read(addr, byte_enables | NP_CMD_CONFIGREAD, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = (data >> (8*n)) & bytemask[size]; + pr_debug("read_config_byte read %#x\n", *value); + return PCIBIOS_SUCCESSFUL; +} + +static int write_config(u8 bus_num, u16 devfn, int where, int size, u32 value) +{ + u32 n, byte_enables, addr, data; + + pr_debug("write_config_byte %#x to %d size %d dev %d:%d:%d\n", value, where, + size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + n = where % 4; + byte_enables = byte_lane_enable_bits(n, size); + if (byte_enables == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + data = value << (8*n); + if (ixp4xx_pci_write(addr, byte_enables | NP_CMD_CONFIGWRITE, data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Generalized PCI config access functions. + */ +static int ixp4xx_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + if (bus->number && !PCI_SLOT(devfn)) + return local_read_config(where, size, value); + return read_config(bus->number, devfn, where, size, value); +} + +static int ixp4xx_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + if (bus->number && !PCI_SLOT(devfn)) + return local_write_config(where, size, value); + return write_config(bus->number, devfn, where, size, value); +} + +struct pci_ops ixp4xx_ops = { + .read = ixp4xx_read_config, + .write = ixp4xx_write_config, +}; + + +/* + * PCI abort handler + */ +static int abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + u32 isr, status; + + isr = *PCI_ISR; + local_read_config(PCI_STATUS, 2, &status); + pr_debug("PCI: abort_handler addr = %#lx, isr = %#x, " + "status = %#x\n", addr, isr, status); + + /* make sure the Master Abort bit is reset */ + *PCI_ISR = PCI_ISR_PFE; + status |= PCI_STATUS_REC_MASTER_ABORT; + local_write_config(PCI_STATUS, 2, status); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + + +/* + * Setup DMA mask to 64MB on PCI devices. Ignore all other devices. + */ +static int ixp4xx_pci_platform_notify(struct device *dev) +{ + if(dev->bus == &pci_bus_type) { + *dev->dma_mask = SZ_64M - 1; + dev->coherent_dma_mask = SZ_64M - 1; + dmabounce_register_dev(dev, 2048, 4096); + } + return 0; +} + +static int ixp4xx_pci_platform_notify_remove(struct device *dev) +{ + if(dev->bus == &pci_bus_type) { + dmabounce_unregister_dev(dev); + } + return 0; +} + +int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M); +} + +void __init ixp4xx_pci_preinit(void) +{ + unsigned long processor_id; + + asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); + + /* + * Determine which PCI read method to use + */ + if (!(processor_id & 0xf)) { + printk("PCI: IXP4xx A0 silicon detected - " + "PCI Non-Prefetch Workaround Enabled\n"); + ixp4xx_pci_read = ixp4xx_pci_read_errata; + } else + ixp4xx_pci_read = ixp4xx_pci_read_no_errata; + + + /* hook in our fault handler for PCI errors */ + hook_fault_code(16+6, abort_handler, SIGBUS, "imprecise external abort"); + + pr_debug("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n"); + + /* + * We use identity AHB->PCI address translation + * in the 0x48000000 to 0x4bffffff address space + */ + *PCI_PCIMEMBASE = 0x48494A4B; + + /* + * We also use identity PCI->AHB address translation + * in 4 16MB BARs that begin at the physical memory start + */ + *PCI_AHBMEMBASE = (PHYS_OFFSET & 0xFF000000) + + ((PHYS_OFFSET & 0xFF000000) >> 8) + + ((PHYS_OFFSET & 0xFF000000) >> 16) + + ((PHYS_OFFSET & 0xFF000000) >> 24) + + 0x00010203; + + if (*PCI_CSR & PCI_CSR_HOST) { + printk("PCI: IXP4xx is host\n"); + + pr_debug("setup BARs in controller\n"); + + /* + * We configure the PCI inbound memory windows to be + * 1:1 mapped to SDRAM + */ + local_write_config(PCI_BASE_ADDRESS_0, 4, PHYS_OFFSET + 0x00000000); + local_write_config(PCI_BASE_ADDRESS_1, 4, PHYS_OFFSET + 0x01000000); + local_write_config(PCI_BASE_ADDRESS_2, 4, PHYS_OFFSET + 0x02000000); + local_write_config(PCI_BASE_ADDRESS_3, 4, PHYS_OFFSET + 0x03000000); + + /* + * Enable CSR window at 0xff000000. + */ + local_write_config(PCI_BASE_ADDRESS_4, 4, 0xff000008); + + /* + * Enable the IO window to be way up high, at 0xfffffc00 + */ + local_write_config(PCI_BASE_ADDRESS_5, 4, 0xfffffc01); + } else { + printk("PCI: IXP4xx is target - No bus scan performed\n"); + } + + printk("PCI: IXP4xx Using %s access for memory space\n", +#ifndef CONFIG_IXP4XX_INDIRECT_PCI + "direct" +#else + "indirect" +#endif + ); + + pr_debug("clear error bits in ISR\n"); + *PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE; + + /* + * Set Initialize Complete in PCI Control Register: allow IXP4XX to + * respond to PCI configuration cycles. Specify that the AHB bus is + * operating in big endian mode. Set up byte lane swapping between + * little-endian PCI and the big-endian AHB bus + */ +#ifdef __ARMEB__ + *PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS; +#else + *PCI_CSR = PCI_CSR_IC; +#endif + + pr_debug("DONE\n"); +} + +int ixp4xx_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if (nr >= 1) + return 0; + + res = kmalloc(sizeof(*res) * 2, GFP_KERNEL); + if (res == NULL) { + /* + * If we're out of memory this early, something is wrong, + * so we might as well catch it here. + */ + panic("PCI: unable to allocate resources?\n"); + } + memset(res, 0, sizeof(*res) * 2); + + local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + + res[0].name = "PCI I/O Space"; + res[0].start = 0x00001000; + res[0].end = 0xffff0000; + res[0].flags = IORESOURCE_IO; + + res[1].name = "PCI Memory Space"; + res[1].start = 0x48000000; +#ifndef CONFIG_IXP4XX_INDIRECT_PCI + res[1].end = 0x4bffffff; +#else + res[1].end = 0x4fffffff; +#endif + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + + platform_notify = ixp4xx_pci_platform_notify; + platform_notify_remove = ixp4xx_pci_platform_notify_remove; + + return 1; +} + +struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys); +} + +/* + * We override these so we properly do dmabounce otherwise drivers + * are able to set the dma_mask to 0xffffffff and we can no longer + * trap bounces. :( + * + * We just return true on everyhing except for < 64MB in which case + * we will fail miseralby and die since we can't handle that case. + */ +int +pci_set_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (mask >= SZ_64M - 1 ) + return 0; + + return -EIO; +} + +int +pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (mask >= SZ_64M - 1 ) + return 0; + + return -EIO; +} + +int +pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (mask >= SZ_64M - 1 ) + return 0; + + return -EIO; +} + +EXPORT_SYMBOL(pci_set_dma_mask); +EXPORT_SYMBOL(pci_dac_set_dma_mask); +EXPORT_SYMBOL(pci_set_consistent_dma_mask); + diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c new file mode 100644 index 000000000..f0166508d --- /dev/null +++ b/arch/arm/mach-ixp4xx/common.c @@ -0,0 +1,263 @@ +/* + * arch/arm/mach-ixp4xx/common.c + * + * Generic code shared across all IXP4XX platforms + * + * Maintainer: Deepak Saxena + * + * Copyright 2002 (c) Intel Corporation + * Copyright 2003-2004 (c) MontaVista, Software, Inc. + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/************************************************************************* + * GPIO acces functions + *************************************************************************/ + +/* + * Configure GPIO line for input, interrupt, or output operation + * + * TODO: Enable/disable the irq_desc based on interrupt or output mode. + * TODO: Should these be named ixp4xx_gpio_? + */ +void gpio_line_config(u8 line, u32 style) +{ + u32 enable; + volatile u32 *int_reg; + u32 int_style; + + enable = *IXP4XX_GPIO_GPOER; + + if (style & IXP4XX_GPIO_OUT) { + enable &= ~((1) << line); + } else if (style & IXP4XX_GPIO_IN) { + enable |= ((1) << line); + + switch (style & IXP4XX_GPIO_INTSTYLE_MASK) + { + case (IXP4XX_GPIO_ACTIVE_HIGH): + int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH; + break; + case (IXP4XX_GPIO_ACTIVE_LOW): + int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW; + break; + case (IXP4XX_GPIO_RISING_EDGE): + int_style = IXP4XX_GPIO_STYLE_RISING_EDGE; + break; + case (IXP4XX_GPIO_FALLING_EDGE): + int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE; + break; + case (IXP4XX_GPIO_TRANSITIONAL): + int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL; + break; + default: + int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH; + break; + } + + if (line >= 8) { /* pins 8-15 */ + line -= 8; + int_reg = IXP4XX_GPIO_GPIT2R; + } + else { /* pins 0-7 */ + int_reg = IXP4XX_GPIO_GPIT1R; + } + + /* Clear the style for the appropriate pin */ + *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR << + (line * IXP4XX_GPIO_STYLE_SIZE)); + + /* Set the new style */ + *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE)); + } + + *IXP4XX_GPIO_GPOER = enable; +} + +EXPORT_SYMBOL(gpio_line_config); + +/************************************************************************* + * IXP4xx chipset I/O mapping + *************************************************************************/ +static struct map_desc ixp4xx_io_desc[] __initdata = { + { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */ + .virtual = IXP4XX_PERIPHERAL_BASE_VIRT, + .physical = IXP4XX_PERIPHERAL_BASE_PHYS, + .length = IXP4XX_PERIPHERAL_REGION_SIZE, + .type = MT_DEVICE + }, { /* Expansion Bus Config Registers */ + .virtual = IXP4XX_EXP_CFG_BASE_VIRT, + .physical = IXP4XX_EXP_CFG_BASE_PHYS, + .length = IXP4XX_EXP_CFG_REGION_SIZE, + .type = MT_DEVICE + }, { /* PCI Registers */ + .virtual = IXP4XX_PCI_CFG_BASE_VIRT, + .physical = IXP4XX_PCI_CFG_BASE_PHYS, + .length = IXP4XX_PCI_CFG_REGION_SIZE, + .type = MT_DEVICE + } +}; + +void __init ixp4xx_map_io(void) +{ + iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc)); +} + + +/************************************************************************* + * IXP4xx chipset IRQ handling + * + * TODO: GPIO IRQs should be marked invalid until the user of the IRQ + * (be it PCI or something else) configures that GPIO line + * as an IRQ. Also, we should use a different chip structure for + * level-based GPIO vs edge-based GPIO. Currently nobody needs this as + * all HW that's publically available uses level IRQs, so we'll + * worry about it if/when we have HW to test. + **************************************************************************/ +static void ixp4xx_irq_mask(unsigned int irq) +{ + *IXP4XX_ICMR &= ~(1 << irq); +} + +static void ixp4xx_irq_mask_ack(unsigned int irq) +{ + ixp4xx_irq_mask(irq); +} + +static void ixp4xx_irq_unmask(unsigned int irq) +{ + static int irq2gpio[NR_IRQS] = { + -1, -1, -1, -1, -1, -1, 0, 1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, -1, -1, + }; + int line = irq2gpio[irq]; + + /* + * This only works for LEVEL gpio IRQs as per the IXP4xx developer's + * manual. If edge-triggered, need to move it to the mask_ack. + * Nobody seems to be using the edge-triggered mode on the GPIOs. + */ + if (line >= 0) + gpio_line_isr_clear(line); + + *IXP4XX_ICMR |= (1 << irq); +} + +static struct irqchip ixp4xx_irq_chip = { + .ack = ixp4xx_irq_mask_ack, + .mask = ixp4xx_irq_mask, + .unmask = ixp4xx_irq_unmask, +}; + +void __init ixp4xx_init_irq(void) +{ + int i = 0; + + /* Route all sources to IRQ instead of FIQ */ + *IXP4XX_ICLR = 0x0; + + /* Disable all interrupt */ + *IXP4XX_ICMR = 0x0; + + for(i = 0; i < NR_IRQS; i++) + { + set_irq_chip(i, &ixp4xx_irq_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID); + } +} + + +/************************************************************************* + * IXP4xx timer tick + * We use OS timer1 on the CPU for the timer tick and the timestamp + * counter as a source of real clock ticks to account for missed jiffies. + *************************************************************************/ + +static unsigned volatile last_jiffy_time; + +#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC) + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long ixp4xx_gettimeoffset(void) +{ + u32 elapsed; + + elapsed = *IXP4XX_OSTS - last_jiffy_time; + + return elapsed / CLOCK_TICKS_PER_USEC; +} + +static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* Clear Pending Interrupt by writing '1' to it */ + *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; + + /* + * Catch up with the real idea of time + */ + do { + do_timer(regs); + last_jiffy_time += LATCH; + } while((*IXP4XX_OSTS - last_jiffy_time) > LATCH); + + return IRQ_HANDLED; +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + .name = "IXP4xx Timer Tick", + .flags = SA_INTERRUPT +}; + +void __init time_init(void) +{ + gettimeoffset = ixp4xx_gettimeoffset; + timer_irq.handler = ixp4xx_timer_interrupt; + + /* Clear Pending Interrupt by writing '1' to it */ + *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; + + /* Setup the Timer counter value */ + *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; + + /* Reset time-stamp counter */ + *IXP4XX_OSTS = 0; + last_jiffy_time = 0; + + /* Connect the interrupt handler and enable the interrupt */ + setup_irq(IRQ_IXP4XX_TIMER1, &timer_irq); +} + + diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c new file mode 100644 index 000000000..b46c74351 --- /dev/null +++ b/arch/arm/mach-ixp4xx/coyote-pci.c @@ -0,0 +1,69 @@ +/* + * arch/arch/mach-ixp4xx/coyote-pci.c + * + * PCI setup routines for ADI Engineering Coyote platform + * + * Copyright (C) 2002 Jungo Software Technologies. + * Copyright (C) 2003 MontaVista Softwrae, Inc. + * + * Maintainer: Deepak Saxena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include + +#include +#include +#include + +#include + +extern void ixp4xx_pci_preinit(void); +extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); +extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys); + +void __init coyote_pci_preinit(void) +{ + gpio_line_config(COYOTE_PCI_SLOT0_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + + gpio_line_config(COYOTE_PCI_SLOT1_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(COYOTE_PCI_SLOT0_PIN); + gpio_line_isr_clear(COYOTE_PCI_SLOT1_PIN); + + ixp4xx_pci_preinit(); +} + +static int __init coyote_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot == COYOTE_PCI_SLOT0_DEVID) + return IRQ_COYOTE_PCI_SLOT0; + else if (slot == COYOTE_PCI_SLOT1_DEVID) + return IRQ_COYOTE_PCI_SLOT1; + else return -1; +} + +struct hw_pci coyote_pci __initdata = { + .nr_controllers = 1, + .preinit = coyote_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = coyote_map_irq, +}; + +int __init coyote_pci_init(void) +{ + if (machine_is_adi_coyote()) + pci_common_init(&coyote_pci); + return 0; +} + +subsys_initcall(coyote_pci_init); diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c new file mode 100644 index 000000000..7baa60c2d --- /dev/null +++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c @@ -0,0 +1,84 @@ +/* + * arch/arm/mach-ixp4xx/ixdp425-pci.c + * + * IXDP425 board-level PCI initialization + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Maintainer: Deepak Saxena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +void __init ixdp425_pci_preinit(void) +{ + gpio_line_config(IXDP425_PCI_INTA_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(IXDP425_PCI_INTB_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(IXDP425_PCI_INTC_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(IXDP425_PCI_INTD_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(IXDP425_PCI_INTA_PIN); + gpio_line_isr_clear(IXDP425_PCI_INTB_PIN); + gpio_line_isr_clear(IXDP425_PCI_INTC_PIN); + gpio_line_isr_clear(IXDP425_PCI_INTD_PIN); + + ixp4xx_pci_preinit(); +} + +static int __init ixdp425_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[IXDP425_PCI_IRQ_LINES] = { + IRQ_IXDP425_PCI_INTA, + IRQ_IXDP425_PCI_INTB, + IRQ_IXDP425_PCI_INTC, + IRQ_IXDP425_PCI_INTD + }; + + int irq = -1; + + if (slot >= 1 && slot <= IXDP425_PCI_MAX_DEV && + pin >= 1 && pin <= IXDP425_PCI_IRQ_LINES) { + irq = pci_irq_table[(slot + pin - 2) % 4]; + } + + return irq; +} + +struct hw_pci ixdp425_pci __initdata = { + .nr_controllers = 1, + .preinit = ixdp425_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = ixdp425_map_irq, +}; + +int __init ixdp425_pci_init(void) +{ + if (machine_is_ixdp425() || + machine_is_ixcdp1100() || + machine_is_avila()) + pci_common_init(&ixdp425_pci); + return 0; +} + +subsys_initcall(ixdp425_pci_init); + diff --git a/arch/arm/mach-ixp4xx/prpmc1100-pci.c b/arch/arm/mach-ixp4xx/prpmc1100-pci.c new file mode 100644 index 000000000..a0aed9ca3 --- /dev/null +++ b/arch/arm/mach-ixp4xx/prpmc1100-pci.c @@ -0,0 +1,119 @@ +/* + * arch/arm/mach-ixp4xx/prpmc1100-pci.c + * + * PrPMC1100 PCI initialization + * + * Copyright (C) 2003-2004 MontaVista Sofwtare, Inc. + * Based on IXDP425 code originally (C) Intel Corporation + * + * Author: Deepak Saxena + * + * PrPMC1100 PCI init code. GPIO usage is similar to that on + * IXDP425, but the IRQ routing is completely different and + * depends on what carrier you are using. This code is written + * to work on the Motorola PrPMC800 ATX carrier board. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include +#include +#include + +#include + + +void __init prpmc1100_pci_preinit(void) +{ + gpio_line_config(PRPMC1100_PCI_INTA_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(PRPMC1100_PCI_INTB_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(PRPMC1100_PCI_INTC_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + gpio_line_config(PRPMC1100_PCI_INTD_PIN, + IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW); + + gpio_line_isr_clear(PRPMC1100_PCI_INTA_PIN); + gpio_line_isr_clear(PRPMC1100_PCI_INTB_PIN); + gpio_line_isr_clear(PRPMC1100_PCI_INTC_PIN); + gpio_line_isr_clear(PRPMC1100_PCI_INTD_PIN); + + ixp4xx_pci_preinit(); +} + + +static int __init prpmc1100_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq = -1; + + static int pci_irq_table[][4] = { + { /* IDSEL 16 - PMC A1 */ + IRQ_PRPMC1100_PCI_INTD, + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB, + IRQ_PRPMC1100_PCI_INTC + }, { /* IDSEL 17 - PRPMC-A-B */ + IRQ_PRPMC1100_PCI_INTD, + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB, + IRQ_PRPMC1100_PCI_INTC + }, { /* IDSEL 18 - PMC A1-B */ + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB, + IRQ_PRPMC1100_PCI_INTC, + IRQ_PRPMC1100_PCI_INTD + }, { /* IDSEL 19 - Unused */ + 0, 0, 0, 0 + }, { /* IDSEL 20 - P2P Bridge */ + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB, + IRQ_PRPMC1100_PCI_INTC, + IRQ_PRPMC1100_PCI_INTD + }, { /* IDSEL 21 - PMC A2 */ + IRQ_PRPMC1100_PCI_INTC, + IRQ_PRPMC1100_PCI_INTD, + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB + }, { /* IDSEL 22 - PMC A2-B */ + IRQ_PRPMC1100_PCI_INTD, + IRQ_PRPMC1100_PCI_INTA, + IRQ_PRPMC1100_PCI_INTB, + IRQ_PRPMC1100_PCI_INTC + }, + }; + + if (slot >= PRPMC1100_PCI_MIN_DEVID && slot <= PRPMC1100_PCI_MAX_DEVID + && pin >= 1 && pin <= PRPMC1100_PCI_IRQ_LINES) { + irq = pci_irq_table[slot - PRPMC1100_PCI_MIN_DEVID][pin - 1]; + } + + return irq; +} + + +struct hw_pci prpmc1100_pci __initdata = { + .nr_controllers = 1, + .preinit = prpmc1100_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = prpmc1100_map_irq, +}; + +int __init prpmc1100_pci_init(void) +{ + if (machine_is_prpmc1100()) + pci_common_init(&prpmc1100_pci); + return 0; +} + +subsys_initcall(prpmc1100_pci_init); + diff --git a/arch/arm/mach-ixp4xx/prpmc1100-setup.c b/arch/arm/mach-ixp4xx/prpmc1100-setup.c new file mode 100644 index 000000000..b0603205d --- /dev/null +++ b/arch/arm/mach-ixp4xx/prpmc1100-setup.c @@ -0,0 +1,90 @@ +/* + * arch/arm/mach-ixp4xx/prpmc1100-setup.c + * + * Motorola PrPMC1100 board setup + * + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Author: Deepak Saxena + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ARMEB__ +#define REG_OFFSET 3 +#else +#define REG_OFFSET 0 +#endif + +/* + * Only one serial port is connected on the PrPMC1100 + */ +static struct uart_port prpmc1100_serial_port = { + .membase = (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET), + .mapbase = (IXP4XX_UART1_BASE_PHYS), + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + .line = 0, + .type = PORT_XSCALE, + .fifosize = 32 +}; + +void __init prpmc1100_map_io(void) +{ + early_serial_setup(&prpmc1100_serial_port); + + ixp4xx_map_io(); +} + +static struct flash_platform_data prpmc1100_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource prpmc1100_flash_resource = { + .start = PRPMC1100_FLASH_BASE, + .end = PRPMC1100_FLASH_BASE + PRPMC1100_FLASH_SIZE, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device prpmc1100_flash_device = { + .name = "IXP4XX-Flash", + .id = 0, + .dev = { + .platform_data = &prpmc1100_flash_data, + }, + .num_resources = 1, + .resource = &prpmc1100_flash_resource, +}; + +static void __init prpmc1100_init(void) +{ + platform_add_device(&prpmc1100_flash_device); +} + +MACHINE_START(PRPMC1100, "Motorola PrPMC1100") + MAINTAINER("MontaVista Software, Inc.") + BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS, + IXP4XX_PERIPHERAL_BASE_VIRT) + MAPIO(prpmc1100_map_io) + INITIRQ(ixp4xx_init_irq) + BOOT_PARAMS(0x0100) + INIT_MACHINE(prpmc1100_init) +MACHINE_END + diff --git a/arch/arm/mach-lh7a40x/Kconfig b/arch/arm/mach-lh7a40x/Kconfig index 4475dba72..b1934bfa4 100644 --- a/arch/arm/mach-lh7a40x/Kconfig +++ b/arch/arm/mach-lh7a40x/Kconfig @@ -1,9 +1,9 @@ +if ARCH_LH7A40X menu "LH7A40X Implementations" config MACH_KEV7A400 bool "KEV7A400" - depends on ARCH_LH7A40X select ARCH_LH7A400 help Say Y here if you are using the Sharp KEV7A400 development @@ -12,9 +12,8 @@ config MACH_KEV7A400 config MACH_LPD7A400 bool "LPD7A400 Card Engine" - depends on ARCH_LH7A40X select ARCH_LH7A400 - select IDE_POLL +# select IDE_POLL help Say Y here if you are using Logic Product Development's LPD7A400 CardEngine. For the time being, the LPD7A400 and @@ -22,9 +21,8 @@ config MACH_LPD7A400 config MACH_LPD7A404 bool "LPD7A404 Card Engine" - depends on ARCH_LH7A40X select ARCH_LH7A404 - select IDE_POLL +# select IDE_POLL help Say Y here if you are using Logic Product Development's LPD7A404 CardEngine. For the time being, the LPD7A400 and @@ -37,3 +35,5 @@ config ARCH_LH7A404 bool endmenu + +endif diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index 734cc7581..75dba9836 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -116,7 +116,12 @@ extern void lpd7a400_map_io (void); static void __init lpd7a40x_init (void) { - CPLD_CONTROL = 0x0; /* Enable LAN (Disable LCD) */ + CPLD_CONTROL |= (1<<6); /* Mask USB1 connection IRQ */ + CPLD_CONTROL &= ~(0 + | (1<<1) /* Disable LCD */ + | (1<<0) /* Enable WLAN */ + ); + platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs)); } @@ -191,7 +196,7 @@ void __init lh7a40x_init_board_irq (void) int pinCPLD = (cpld_version == 0x28) ? 7 : 3; #if defined CONFIG_MACH_LPD7A404 - cpld_version = 0x34; /* Override, for now */ + cpld_version = 0x34; /* Coerce LPD7A404 to RevB */ #endif /* First, configure user controlled GPIOF interrupts */ @@ -204,7 +209,7 @@ void __init lh7a40x_init_board_irq (void) /* Then, configure CPLD interrupt */ - CPLD_INTERRUPTS = 0x0c; /* Disable all CPLD interrupts */ + CPLD_INTERRUPTS = 0x9c; /* Disable all CPLD interrupts */ GPIO_PFDD &= ~(1 << pinCPLD); /* Make input */ GPIO_INTTYPE1 |= (1 << pinCPLD); /* Edge triggered */ GPIO_INTTYPE2 &= ~(1 << pinCPLD); /* Active low */ diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index 30bc6dff3..9fb70d5dc 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -1,27 +1,24 @@ +if ARCH_OMAP menu "TI OMAP Implementations" comment "OMAP Core Type" config ARCH_OMAP730 - depends on ARCH_OMAP bool "OMAP730 Based System" select CPU_ARM926T config ARCH_OMAP1510 - depends on ARCH_OMAP default y bool "OMAP1510 Based System" select CPU_ARM925T select CPU_DCACHE_WRITETHROUGH config ARCH_OMAP1610 - depends on ARCH_OMAP bool "OMAP1610 Based System" select CPU_ARM926T config ARCH_OMAP5912 - depends on ARCH_OMAP bool "OMAP5912 Based System" select CPU_ARM926T @@ -87,7 +84,6 @@ comment "OMAP Feature Selections" #config OMAP_BOOT_TAG # bool "OMAP bootloader information passing" -# depends on ARCH_OMAP # default n # help # Say Y, if you have a bootloader which passes information @@ -95,7 +91,6 @@ comment "OMAP Feature Selections" config OMAP_MUX bool "OMAP multiplexing support" - depends on ARCH_OMAP default y help Pin multiplexing support for OMAP boards. If your bootloader @@ -113,7 +108,6 @@ config OMAP_MUX_DEBUG choice prompt "Low-level debug console UART" - depends on ARCH_OMAP default OMAP_LL_DEBUG_UART1 config OMAP_LL_DEBUG_UART1 @@ -171,3 +165,5 @@ config OMAP_ARM_30MHZ Enable 30MHz clock for OMAP CPU. If unsure, say N. endmenu + +endif diff --git a/arch/arm/mach-omap/clocks.c b/arch/arm/mach-omap/clocks.c index 382baee25..bda7c6f38 100644 --- a/arch/arm/mach-omap/clocks.c +++ b/arch/arm/mach-omap/clocks.c @@ -84,7 +84,7 @@ static ck_info_t ck_info_table[] = { }, { .name = "ck_gen1", .flags = CK_RATEF | CK_IDLEF, - .rate_reg = CK_DPLL1, + .rate_reg = DPLL_CTL, .idle_reg = ARM_IDLECT1, .idle_shift = IDLDPLL_ARM, .parent = OMAP_CLKIN, @@ -629,39 +629,39 @@ init_ck(void) omap_writew(0x1000, ARM_SYSST); #if defined(CONFIG_OMAP_ARM_30MHZ) omap_writew(0x1555, ARM_CKCTL); - omap_writew(0x2290, DPLL_CTL_REG); + omap_writew(0x2290, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_60MHZ) omap_writew(0x1005, ARM_CKCTL); - omap_writew(0x2290, DPLL_CTL_REG); + omap_writew(0x2290, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_96MHZ) omap_writew(0x1005, ARM_CKCTL); - omap_writew(0x2410, DPLL_CTL_REG); + omap_writew(0x2410, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_120MHZ) omap_writew(0x110a, ARM_CKCTL); - omap_writew(0x2510, DPLL_CTL_REG); + omap_writew(0x2510, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_168MHZ) omap_writew(0x110f, ARM_CKCTL); - omap_writew(0x2710, DPLL_CTL_REG); + omap_writew(0x2710, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730) omap_writew(0x250E, ARM_CKCTL); - omap_writew(0x2710, DPLL_CTL_REG); + omap_writew(0x2710, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)) omap_writew(0x150f, ARM_CKCTL); if (crystal_type == 2) { source_clock = 13; /* MHz */ - omap_writew(0x2510, DPLL_CTL_REG); + omap_writew(0x2510, DPLL_CTL); } else - omap_writew(0x2810, DPLL_CTL_REG); + omap_writew(0x2810, DPLL_CTL); #elif defined(CONFIG_OMAP_ARM_195MHZ) && defined(CONFIG_ARCH_OMAP730) omap_writew(0x250E, ARM_CKCTL); - omap_writew(0x2790, DPLL_CTL_REG); + omap_writew(0x2790, DPLL_CTL); #else #error "OMAP MHZ not set, please run make xconfig" #endif #ifdef CONFIG_MACH_OMAP_PERSEUS2 /* Select slicer output as OMAP input clock */ - omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL_REG) & ~0x1, OMAP730_PCC_UPLD_CTRL_REG); + omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); #endif /* Turn off some other junk the bootloader might have turned on */ diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c index 2ff74d1a4..43aaa1c6c 100644 --- a/arch/arm/mach-omap/common.c +++ b/arch/arm/mach-omap/common.c @@ -23,6 +23,58 @@ #include #include +/* + * ---------------------------------------------------------------------------- + * OMAP revision check + * + * Since we use the cpu_is_omapnnnn() macros, there's a chance that a board + * switches to an updated core. We want to print out the OMAP revision early. + * + * We use the system_serial registers for the revision information so we + * can see it in /proc/cpuinfo. + * + * If the OMAP detection gets more complicated, we may want to expand this + * to store the OMAP version and replace the current cpu_is_omapnnnn() macros. + * + * ---------------------------------------------------------------------------- + */ +static void __init omap_check_revision(void) +{ + system_serial_high = omap_readl(OMAP_ID_BASE); + system_serial_low = OMAP_ID_REG; + system_rev = (OMAP_ID_REG >> ID_SHIFT) & ID_MASK; + + printk("OMAP revision: %d.%d (0x%08x) id: 0x%08x detected as OMAP-", + (system_serial_high >> 20) & 0xf, + (system_serial_high >> 16) & 0xf, + system_serial_high, system_serial_low); + + switch (system_rev) { + case OMAP_ID_730: + printk("730\n"); + system_rev = 0x730; + break; + case OMAP_ID_1510: + printk("1510\n"); + system_rev = 0x1510; + break; + case OMAP_ID_1610: + printk("1610\n"); + system_rev = 0x1610; + break; + case OMAP_ID_1710: + printk("1710\n"); + system_rev = 0x1710; + break; + case OMAP_ID_5912: + printk("5912/1611B\n"); + system_rev = 0x5912; + break; + default: + printk("unknown, please add support!\n"); + } +} + /* * ---------------------------------------------------------------------------- * OMAP I/O mapping @@ -64,7 +116,13 @@ static struct map_desc omap1610_io_desc[] __initdata = { static struct map_desc omap5912_io_desc[] __initdata = { { OMAP5912_DSP_BASE, OMAP5912_DSP_START, OMAP5912_DSP_SIZE, MT_DEVICE }, { OMAP5912_DSPREG_BASE, OMAP5912_DSPREG_START, OMAP5912_DSPREG_SIZE, MT_DEVICE }, - { OMAP5912_SRAM_BASE, OMAP5912_SRAM_START, OMAP5912_SRAM_SIZE, MT_DEVICE } +/* + * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page + * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped. + * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte + * can be used. + */ + { OMAP5912_SRAM_BASE, OMAP5912_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE } }; #endif @@ -77,6 +135,7 @@ static void __init _omap_map_io(void) /* We have to initialize the IO space mapping before we can run * cpu_is_omapxxx() macros. */ iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc)); + omap_check_revision(); #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { @@ -102,8 +161,8 @@ static void __init _omap_map_io(void) /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort * on a Posted Write in the TIPB Bridge". */ - omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL_REG); - omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL_REG); + omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL); + omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL); /* Must init clocks early to assure that timer interrupt works */ diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c index 95b21e2f4..d9246b1dc 100644 --- a/arch/arm/mach-omap/fpga.c +++ b/arch/arm/mach-omap/fpga.c @@ -46,11 +46,11 @@ static void fpga_mask_irq(unsigned int irq) irq -= IH_FPGA_BASE; if (irq < 8) - __raw_writeb((__raw_readb(OMAP1510P1_FPGA_IMR_LO) - & ~(1 << irq)), OMAP1510P1_FPGA_IMR_LO); + __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) + & ~(1 << irq)), OMAP1510_FPGA_IMR_LO); else if (irq < 16) - __raw_writeb((__raw_readb(OMAP1510P1_FPGA_IMR_HI) - & ~(1 << (irq - 8))), OMAP1510P1_FPGA_IMR_HI); + __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) + & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); else __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2); @@ -60,10 +60,10 @@ static void fpga_mask_irq(unsigned int irq) static inline u32 get_fpga_unmasked_irqs(void) { return - ((__raw_readb(OMAP1510P1_FPGA_ISR_LO) & - __raw_readb(OMAP1510P1_FPGA_IMR_LO))) | - ((__raw_readb(OMAP1510P1_FPGA_ISR_HI) & - __raw_readb(OMAP1510P1_FPGA_IMR_HI)) << 8) | + ((__raw_readb(OMAP1510_FPGA_ISR_LO) & + __raw_readb(OMAP1510_FPGA_IMR_LO))) | + ((__raw_readb(OMAP1510_FPGA_ISR_HI) & + __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) | ((__raw_readb(INNOVATOR_FPGA_ISR2) & __raw_readb(INNOVATOR_FPGA_IMR2)) << 16); } @@ -79,11 +79,11 @@ static void fpga_unmask_irq(unsigned int irq) irq -= IH_FPGA_BASE; if (irq < 8) - __raw_writeb((__raw_readb(OMAP1510P1_FPGA_IMR_LO) | (1 << irq)), - OMAP1510P1_FPGA_IMR_LO); + __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), + OMAP1510_FPGA_IMR_LO); else if (irq < 16) - __raw_writeb((__raw_readb(OMAP1510P1_FPGA_IMR_HI) - | (1 << (irq - 8))), OMAP1510P1_FPGA_IMR_HI); + __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) + | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); else __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2); @@ -166,8 +166,8 @@ void fpga_init_irq(void) { int i; - __raw_writeb(0, OMAP1510P1_FPGA_IMR_LO); - __raw_writeb(0, OMAP1510P1_FPGA_IMR_HI); + __raw_writeb(0, OMAP1510_FPGA_IMR_LO); + __raw_writeb(0, OMAP1510_FPGA_IMR_HI); __raw_writeb(0, INNOVATOR_FPGA_IMR2); for (i = IH_FPGA_BASE; i < (IH_FPGA_BASE + NR_FPGA_IRQS); i++) { diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c index e7087bc24..944c29418 100644 --- a/arch/arm/mach-omap/ocpi.c +++ b/arch/arm/mach-omap/ocpi.c @@ -85,14 +85,6 @@ int ocpi_enable(void) val &= ~0xff; omap_writel(val, OCPI_SEC); - val = omap_readl(OCPI_SEC); - val |= 0; - omap_writel(val, OCPI_SEC); - - val = omap_readl(OCPI_SINT0); - val |= 0; - omap_writel(val, OCPI_SINT1); - return 0; } EXPORT_SYMBOL(ocpi_enable); diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 5e6468a5a..706858ea2 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -27,6 +27,8 @@ #include #include +#include + #include "generic.h" #ifndef PXA_IDP_REV02 diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c index 8f9d2c3c7..adb108c6c 100644 --- a/arch/arm/mach-pxa/leds-idp.c +++ b/arch/arm/mach-pxa/leds-idp.c @@ -19,6 +19,8 @@ #include #include +#include + #include "leds.h" #define LED_STATE_ENABLED 1 diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c index cb6f6ddb0..8403f6780 100644 --- a/arch/arm/mach-pxa/leds-mainstone.c +++ b/arch/arm/mach-pxa/leds-mainstone.c @@ -17,6 +17,8 @@ #include #include +#include + #include "leds.h" diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index cd7da1ddf..663c1eef8 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -30,6 +30,8 @@ #include #include +#include + #include "generic.h" diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index f57c96222..41150917f 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -83,12 +83,21 @@ unsigned int get_clk_frequency_khz(int info) EXPORT_SYMBOL(get_clk_frequency_khz); /* - * Return the current lclk requency in units of 10kHz + * Return the current memory clock frequency in units of 10kHz */ -unsigned int get_lclk_frequency_10khz(void) +unsigned int get_memclk_frequency_10khz(void) { return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; } -EXPORT_SYMBOL(get_lclk_frequency_10khz); +EXPORT_SYMBOL(get_memclk_frequency_10khz); +/* + * Return the current LCD clock frequency in units of 10kHz + */ +unsigned int get_lcdclk_frequency_10khz(void) +{ + return get_memclk_frequency_10khz(); +} + +EXPORT_SYMBOL(get_lcdclk_frequency_10khz); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 1addceb0f..b1573c837 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -21,100 +21,98 @@ #include "generic.h" -/* Crystal clock : 13-MHZ*/ +/* Crystal clock: 13MHz */ #define BASE_CLK 13000000 /* * Get the clock frequency as reflected by CCSR and the turbo flag. * We assume these values have been applied via a fcs. * If info is not 0 we also display the current settings. - * - * For more details, refer to Bulverde Manual, section 3.8.2.1 */ unsigned int get_clk_frequency_khz( int info) { - unsigned long ccsr, turbo, b, ht; - unsigned int l, L, m, M, n2, N, S, cccra; + unsigned long ccsr, clkcfg; + unsigned int l, L, m, M, n2, N, S; + int cccr_a, t, ht, b; ccsr = CCSR; - cccra = CCCR & (0x1 << 25); + cccr_a = CCCR & (1 << 25); /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ - asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) ); - b = (turbo & (0x1 << 3)); - ht = (turbo & (0x1 << 2)); + asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); + t = clkcfg & (1 << 1); + ht = clkcfg & (1 << 2); + b = clkcfg & (1 << 3); l = ccsr & 0x1f; n2 = (ccsr>>7) & 0xf; - if (l == 31) { - /* The calculation from the Yellow Book is incorrect: - it says M=4 for L=21-30 (which is easy to calculate - by subtracting 1 and then dividing by 10, but not - with 31, so we'll do it manually */ - m = 1 << 2; - } else { - m = 1 << ((l-1)/10); - } + m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; - L = l * BASE_CLK; - N = (n2 * L) / 2; - S = (b) ? L : (L/2); - if (cccra == 0) - M = L/m; - else - M = (b) ? L : (L/2); + L = l * BASE_CLK; + N = (L * n2) / 2; + M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2)); + S = (b) ? L : (L/2); if (info) { printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", L / 1000000, (L % 1000000) / 10000, l ); - printk( KERN_INFO "Memory clock: %d.%02dMHz (/%d)\n", - M / 1000000, (M % 1000000) / 10000, m ); printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", N / 1000000, (N % 1000000)/10000, n2 / 2, (n2 % 2)*5, - (turbo & 1) ? "" : "in" ); + (t) ? "" : "in" ); + printk( KERN_INFO "Memory clock: %d.%02dMHz (/%d)\n", + M / 1000000, (M % 1000000) / 10000, m ); printk( KERN_INFO "System bus clock: %d.%02dMHz \n", S / 1000000, (S % 1000000) / 10000 ); } - return (turbo & 1) ? (N/1000) : (L/1000); + return (t) ? (N/1000) : (L/1000); } /* * Return the current mem clock frequency in units of 10kHz as * reflected by CCCR[A], B, and L */ -unsigned int get_lclk_frequency_10khz(void) +unsigned int get_memclk_frequency_10khz(void) { - unsigned long ccsr, clkcfg, b; - unsigned int l, L, m, M, cccra; + unsigned long ccsr, clkcfg; + unsigned int l, L, m, M; + int cccr_a, b; - cccra = CCCR & (0x1 << 25); + ccsr = CCSR; + cccr_a = CCCR & (1 << 25); - /* Read clkcfg register to obtain b */ + /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); - b = (clkcfg & (0x1 << 3)); + b = clkcfg & (1 << 3); - ccsr = CCSR; - l = ccsr & 0x1f; - if (l == 31) { - /* The calculation from the Yellow Book is incorrect: - it says M=4 for L=21-30 (which is easy to calculate - by subtracting 1 and then dividing by 10, but not - with 31, so we'll do it manually */ - m = 1 << 2; - } else { - m = 1 << ((l-1)/10); - } + l = ccsr & 0x1f; + m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; L = l * BASE_CLK; - if (cccra == 0) - M = L/m; - else - M = (b) ? L : L/2; + M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2)); return (M / 10000); } -EXPORT_SYMBOL(get_clk_frequency_khz); -EXPORT_SYMBOL(get_lclk_frequency_10khz); +/* + * Return the current LCD clock frequency in units of 10kHz as + */ +unsigned int get_lcdclk_frequency_10khz(void) +{ + unsigned long ccsr; + unsigned int l, L, k, K; + + ccsr = CCSR; + l = ccsr & 0x1f; + k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4; + + L = l * BASE_CLK; + K = L / k; + + return (K / 10000); +} + +EXPORT_SYMBOL(get_clk_frequency_khz); +EXPORT_SYMBOL(get_memclk_frequency_10khz); +EXPORT_SYMBOL(get_lcdclk_frequency_10khz); diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c new file mode 100644 index 000000000..4e0282b12 --- /dev/null +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -0,0 +1,109 @@ +/*********************************************************************** + * + * linux/arch/arm/mach-s3c2410/mach-smdk2410.c + * + * Copyright (C) 2004 by FS Forth-Systeme GmbH + * All rights reserved. + * + * $Id: mach-smdk2410.c,v 1.1 2004/05/11 14:15:38 mpietrek Exp $ + * @Author: Jonas Dietsche + * + * 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 + * + * @History: + * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by + * Ben Dooks + ***********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "s3c2410.h" + + +static struct map_desc smdk2410_iodesc[] __initdata = { + /* nothing here yet */ +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +/* base baud rate for all our UARTs */ +static unsigned long smdk2410_serial_clock = 24*1000*1000; + +static struct s3c2410_uartcfg smdk2410_uartcfgs[] = { + [0] = { + .hwport = 0, + .flags = 0, + .clock = &smdk2410_serial_clock, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [1] = { + .hwport = 1, + .flags = 0, + .clock = &smdk2410_serial_clock, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [2] = { + .hwport = 2, + .flags = 0, + .clock = &smdk2410_serial_clock, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + } +}; + + +void __init smdk2410_map_io(void) +{ + s3c2410_map_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); + s3c2410_uartcfgs = smdk2410_uartcfgs; +} + +void __init smdk2410_init_irq(void) +{ + s3c2410_init_irq(); +} + +MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch + * to SMDK2410 */ + MAINTAINER("Jonas Dietsche") + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) + MAPIO(smdk2410_map_io) + INITIRQ(smdk2410_init_irq) +MACHINE_END diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index 6d9249bfc..ce21b9838 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -1,9 +1,9 @@ +if ARCH_SA1100 menu "SA11x0 Implementations" config SA1100_ASSABET bool "Assabet" - depends on ARCH_SA1100 help Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 Microprocessor Development Board (also known as the Assabet). @@ -18,7 +18,6 @@ config ASSABET_NEPONSET config SA1100_ADSBITSY bool "ADS Bitsy" - depends on ARCH_SA1100 help Say Y here if you are using Applied Data Systems Intel(R) StrongARM(R) 1110 based Bitsy, 3 x 5 inches in size, Compaq - IPAQ - @@ -28,14 +27,12 @@ config SA1100_ADSBITSY config SA1100_BRUTUS bool "Brutus" - depends on ARCH_SA1100 help Say Y here if you are using the Intel(R) StrongARM(R) SA-1100 Microprocessor Development Board (also known as the Brutus). config SA1100_CERF bool "CerfBoard" - depends on ARCH_SA1100 help The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued). More information is available at: @@ -62,7 +59,6 @@ endchoice config SA1100_H3100 bool "Compaq iPAQ H3100" - depends on ARCH_SA1100 help Say Y here if you intend to run this kernel on the Compaq iPAQ H3100 handheld computer. Information about this machine and the @@ -73,7 +69,6 @@ config SA1100_H3100 config SA1100_H3600 bool "Compaq iPAQ H3600/H3700" - depends on ARCH_SA1100 help Say Y here if you intend to run this kernel on the Compaq iPAQ H3600 handheld computer. Information about this machine and the @@ -84,7 +79,6 @@ config SA1100_H3600 config SA1100_H3800 bool "Compaq iPAQ H3800" - depends on ARCH_SA1100 help Say Y here if you intend to run this kernel on the Compaq iPAQ H3800 series handheld computer. Information about this machine and the @@ -102,7 +96,6 @@ config SA1100_H3XXX #dep_bool ' Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100 config SA1100_EXTENEX1 bool "Extenex HandHeld Theater (Squashtail)" - depends on ARCH_SA1100 config SA1100_EXTENEX1_16MB bool "Support 16 MB of DRAM (not just 8)" @@ -110,7 +103,6 @@ config SA1100_EXTENEX1_16MB config SA1100_FLEXANET bool "FlexaNet" - depends on ARCH_SA1100 help Say Y here if you intend to run this kernel on the FlexaNet handheld instruments. Information about this machine can be @@ -118,14 +110,12 @@ config SA1100_FLEXANET config SA1100_FREEBIRD bool "FreeBird-v1.1" - depends on ARCH_SA1100 help Support the FreeBird board used in Coventive embedded products. See Documentation/arm/SA1100/Freebird for more. config SA1100_GRAPHICSCLIENT bool "GraphicsClient Plus" - depends on ARCH_SA1100 help Say Y here if you are using an Applied Data Systems Intel(R) StrongARM(R) SA-1100 based Graphics Client SBC. See @@ -133,7 +123,6 @@ config SA1100_GRAPHICSCLIENT config SA1100_GRAPHICSMASTER bool "GraphicsMaster" - depends on ARCH_SA1100 help Say Y here if you are using an Applied Data Systems Intel(R) StrongARM(R) SA-1100 based Graphics Master SBC with SA-1111 @@ -143,14 +132,12 @@ config SA1100_GRAPHICSMASTER config SA1100_BADGE4 bool "HP Labs BadgePAD 4" - depends on ARCH_SA1100 help Say Y here if you want to build a kernel for the HP Laboratories BadgePAD 4. config SA1100_JORNADA720 bool "HP Jornada 720" - depends on ARCH_SA1100 help Say Y here if you want to build a kernel for the HP Jornada 720 handheld computer. See @@ -158,14 +145,12 @@ config SA1100_JORNADA720 config SA1100_HACKKIT bool "HackKit Core CPU Board" - depends on ARCH_SA1100 help Say Y here to support the HackKit Core CPU Board ; config SA1100_HUW_WEBPANEL bool "HuW WebPanel" - depends on ARCH_SA1100 help Say Y here to support the HuW Webpanel produced by Hoeft & Wessel AG. English-language website is at @@ -174,7 +159,6 @@ config SA1100_HUW_WEBPANEL config SA1100_ITSY bool "Itsy" - depends on ARCH_SA1100 help Say Y here if you are using the Compaq Itsy experimental pocket computer. See for @@ -182,7 +166,6 @@ config SA1100_ITSY config SA1100_LART bool "LART" - depends on ARCH_SA1100 help Say Y here if you are using the Linux Advanced Radio Terminal (also known as the LART). See for @@ -190,7 +173,6 @@ config SA1100_LART config SA1100_NANOENGINE bool "nanoEngine" - depends on ARCH_SA1100 help The nanoEngine is a StrongARM 1110-based single board computer from Bright Star Engineering. More information is available at: @@ -201,14 +183,12 @@ config SA1100_NANOENGINE config SA1100_OMNIMETER bool "OmniMeter" - depends on ARCH_SA1100 help Say Y here if you are using the inhand electronics OmniMeter. See for details. config SA1100_PANGOLIN bool "Pangolin" - depends on ARCH_SA1100 help Pangolin is a StrongARM 1110-based evaluation platform produced by Dialogue Technology. It has EISA slots for ease of configuration @@ -220,7 +200,6 @@ config SA1100_PANGOLIN config SA1100_PLEB bool "PLEB" - depends on ARCH_SA1100 help Say Y here if you are using a Portable Linux Embedded Board (also known as PLEB). See @@ -228,7 +207,6 @@ config SA1100_PLEB config SA1100_PT_SYSTEM3 bool "PT System 3" - depends on ARCH_SA1100 help Say Y here if you intend to build a kernel suitable to run on a Pruftechnik Digital Board. For more information see @@ -236,7 +214,6 @@ config SA1100_PT_SYSTEM3 config SA1100_SHANNON bool "Shannon" - depends on ARCH_SA1100 help The Shannon (also known as a Tuxscreen, and also as a IS2630) was a limited edition webphone produced by Philips. The Shannon is a SA1100 @@ -245,7 +222,6 @@ config SA1100_SHANNON config SA1100_SHERMAN bool "Sherman" - depends on ARCH_SA1100 help Say Y here to support the Blazie Engineering `Sherman' StrongARM 1110-based SBC, used primarily in assistance products for the @@ -255,7 +231,6 @@ config SA1100_SHERMAN config SA1100_SIMPAD bool "Simpad" - depends on ARCH_SA1100 help The SIEMENS webpad SIMpad is based on the StrongARM 1110. There are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB @@ -266,7 +241,6 @@ config SA1100_SIMPAD config SA1100_PFS168 bool "Tulsa" - depends on ARCH_SA1100 help The Radisys Corp. PFS-168 (aka Tulsa) is an Intel® StrongArm® SA-1110 based computer which includes the SA-1111 Microprocessor Companion Chip and other @@ -276,7 +250,6 @@ config SA1100_PFS168 config SA1100_VICTOR bool "Victor" - depends on ARCH_SA1100 help Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) SA-1100 based Victor Digital Talking Book Reader. See @@ -285,14 +258,12 @@ config SA1100_VICTOR config SA1100_XP860 bool "XP860" - depends on ARCH_SA1100 help :: Config help missing :: :: 06 August 2002 :: config SA1100_YOPY bool "Yopy" - depends on ARCH_SA1100 help Say Y here to support the Yopy PDA. Product information at . See Documentation/arm/SA1100/Yopy @@ -300,14 +271,12 @@ config SA1100_YOPY config SA1100_STORK bool "Stork" - depends on ARCH_SA1100 help Say Y here if you intend to run this kernel on the Stork handheld computer. #config SA1100_TRIZEPS # bool "Trizeps" -# depends on ARCH_SA1100 # help # :: write me :: @@ -319,7 +288,6 @@ config SA1100_STORK config SA1100_SSP tristate "Generic PIO SSP" - depends on ARCH_SA1100 help Say Y here to enable support for the generic PIO SSP driver. This isn't for audio support, but for attached sensors and @@ -328,7 +296,6 @@ config SA1100_SSP config SA1100_USB tristate "SA1100 USB function support" - depends on ARCH_SA1100 config SA1100_USB_NETLINK tristate "Support for SA11x0 USB network link function" @@ -349,3 +316,4 @@ config H3600_SLEEVE endmenu +endif diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index c306fc469..c00061769 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -348,7 +348,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr, if (pmd_none(*pmd_k)) goto bad_area; - set_pmd(pmd, *pmd_k); + copy_pmd(pmd, pmd_k); return 0; bad_area: diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index eec9d7b00..32c4b0e35 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -40,7 +40,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, */ cache_type = read_cpuid(CPUID_CACHETYPE); if (cache_type != read_cpuid(CPUID_ID)) { - aliasing = (cache_type | cache_type >> 12) & (1 << 9); + aliasing = (cache_type | cache_type >> 12) & (1 << 11); if (aliasing) do_align = filp || flags & MAP_SHARED; } diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index e73c74803..8df666f8d 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -14,8 +14,6 @@ #include #include -EXPORT_SYMBOL(__flush_dcache_page); - #ifndef MULTI_CPU EXPORT_SYMBOL(cpu_dcache_clean_area); EXPORT_SYMBOL(cpu_set_pte); @@ -28,7 +26,6 @@ EXPORT_SYMBOL_NOVERS(__cpuc_flush_kern_all); EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_all); EXPORT_SYMBOL_NOVERS(__cpuc_flush_user_range); EXPORT_SYMBOL_NOVERS(__cpuc_coherent_kern_range); -EXPORT_SYMBOL_NOVERS(__cpuc_flush_dcache_page); #else EXPORT_SYMBOL(cpu_cache); #endif diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 2a594d21d..2ecfdfd61 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Thu Apr 29 19:06:33 2004 +# Last update: Fri May 28 13:17:46 2004 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -509,7 +509,7 @@ s3c5500 MACH_S3C5500 S3C5500 498 smdk5500 MACH_SMDK5500 SMDK5500 499 signalsync MACH_SIGNALSYNC SIGNALSYNC 500 nbc MACH_NBC NBC 501 -er4525 MACH_ER4525 ER4525 502 +kodiak MACH_KODIAK KODIAK 502 netbookpro MACH_NETBOOKPRO NETBOOKPRO 503 hw90200 MACH_HW90200 HW90200 504 condor MACH_CONDOR CONDOR 505 @@ -533,3 +533,16 @@ emc1000 MACH_EMC1000 EMC1000 522 tidsc25 MACH_TIDSC25 TIDSC25 523 akcpmxl MACH_AKCPMXL AKCPMXL 524 av3xx MACH_AV3XX AV3XX 525 +avila MACH_AVILA AVILA 526 +pxa_mpm10 MACH_PXA_MPM10 PXA_MPM10 527 +pxa_kyanite MACH_PXA_KYANITE PXA_KYANITE 528 +sgold MACH_SGOLD SGOLD 529 +oscar MACH_OSCAR OSCAR 530 +epxa4usb2 MACH_EPXA4USB2 EPXA4USB2 531 +xsengine MACH_XSENGINE XSENGINE 532 +ip600 MACH_IP600 IP600 533 +mcan2 MACH_MCAN2 MCAN2 534 +ddi_blueridge MACH_DDI_BLUERIDGE DDI_BLUERIDGE 535 +skyminder MACH_SKYMINDER SKYMINDER 536 +lpd79520 MACH_LPD79520 LPD79520 537 +edb9302 MACH_EDB9302 EDB9302 538 diff --git a/arch/cris/arch-v10/drivers/ide.c b/arch/cris/arch-v10/drivers/ide.c new file mode 100644 index 000000000..335473c45 --- /dev/null +++ b/arch/cris/arch-v10/drivers/ide.c @@ -0,0 +1,945 @@ +/* $Id: ide.c,v 1.1 2004/01/22 08:22:58 starvik Exp $ + * + * Etrax specific IDE functions, like init and PIO-mode setting etc. + * Almost the entire ide.c is used for the rest of the Etrax ATA driver. + * Copyright (c) 2000-2004 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Mikael Starvik (pio setup stuff, Linux 2.6 port) + */ + +/* Regarding DMA: + * + * There are two forms of DMA - "DMA handshaking" between the interface and the drive, + * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's + * something built-in in the Etrax. However only some drives support the DMA-mode handshaking + * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the + * device can't do DMA handshaking for some stupid reason. We don't need to do that. + */ + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* number of Etrax DMA descriptors */ +#define MAX_DMA_DESCRS 64 + +/* number of times to retry busy-flags when reading/writing IDE-registers + * this can't be too high because a hung harddisk might cause the watchdog + * to trigger (sometimes INB and OUTB are called with irq's disabled) + */ + +#define IDE_REGISTER_TIMEOUT 300 + +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET +/* address where the memory-mapped IDE reset bit lives, if used */ +static volatile unsigned long *reset_addr; +#endif + +static int e100_read_command = 0; + +#define LOWDB(x) +#define D(x) + +void +etrax100_ide_outw(unsigned short data, ide_ioreg_t reg) { + int timeleft; + LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg)); + + /* note the lack of handling any timeouts. we stop waiting, but we don't + * really notify anybody. + */ + + timeleft = IDE_REGISTER_TIMEOUT; + /* wait for busy flag */ + while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))) + timeleft--; + + /* + * Fall through at a timeout, so the ongoing command will be + * aborted by the write below, which is expected to be a dummy + * command to the command register. This happens when a faulty + * drive times out on a command. See comment on timeout in + * INB. + */ + if(!timeleft) + printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data); + + *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */ + + timeleft = IDE_REGISTER_TIMEOUT; + /* wait for transmitter ready */ + while(timeleft && !(*R_ATA_STATUS_DATA & + IO_MASK(R_ATA_STATUS_DATA, tr_rdy))) + timeleft--; +} + +void +etrax100_ide_outb(unsigned char data, ide_ioreg_t reg) +{ + etrax100_ide_outw(data, reg); +} + +void +etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port) +{ + etrax100_ide_outw(addr, port); +} + +unsigned short +etrax100_ide_inw(ide_ioreg_t reg) { + int status; + int timeleft; + + timeleft = IDE_REGISTER_TIMEOUT; + /* wait for busy flag */ + while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))) + timeleft--; + + if(!timeleft) { + /* + * If we're asked to read the status register, like for + * example when a command does not complete for an + * extended time, but the ATA interface is stuck in a + * busy state at the *ETRAX* ATA interface level (as has + * happened repeatedly with at least one bad disk), then + * the best thing to do is to pretend that we read + * "busy" in the status register, so the IDE driver will + * time-out, abort the ongoing command and perform a + * reset sequence. Note that the subsequent OUT_BYTE + * call will also timeout on busy, but as long as the + * write is still performed, everything will be fine. + */ + if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr)) + == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET)) + return BUSY_STAT; + else + /* For other rare cases we assume 0 is good enough. */ + return 0; + } + + *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */ + + timeleft = IDE_REGISTER_TIMEOUT; + /* wait for available */ + while(timeleft && !((status = *R_ATA_STATUS_DATA) & + IO_MASK(R_ATA_STATUS_DATA, dav))) + timeleft--; + + if(!timeleft) + return 0; + + LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg)); + + return (unsigned short)status; +} + +unsigned char +etrax100_ide_inb(ide_ioreg_t reg) +{ + return (unsigned char)etrax100_ide_inw(reg); +} + +/* PIO timing (in R_ATA_CONFIG) + * + * _____________________________ + * ADDRESS : ________/ + * + * _______________ + * DIOR : ____________/ \__________ + * + * _______________ + * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX + * + * + * DIOR is unbuffered while address and data is buffered. + * This creates two problems: + * 1. The DIOR pulse is to early (because it is unbuffered) + * 2. The rise time of DIOR is long + * + * There are at least three different plausible solutions + * 1. Use a pad capable of larger currents in Etrax + * 2. Use an external buffer + * 3. Make the strobe pulse longer + * + * Some of the strobe timings below are modified to compensate + * for this. This implies a slight performance decrease. + * + * THIS SHOULD NEVER BE CHANGED! + * + * TODO: Is this true for the latest LX boards still ? + */ + +#define ATA_DMA2_STROBE 4 +#define ATA_DMA2_HOLD 0 +#define ATA_DMA1_STROBE 4 +#define ATA_DMA1_HOLD 1 +#define ATA_DMA0_STROBE 12 +#define ATA_DMA0_HOLD 9 +#define ATA_PIO4_SETUP 1 +#define ATA_PIO4_STROBE 5 +#define ATA_PIO4_HOLD 0 +#define ATA_PIO3_SETUP 1 +#define ATA_PIO3_STROBE 5 +#define ATA_PIO3_HOLD 1 +#define ATA_PIO2_SETUP 1 +#define ATA_PIO2_STROBE 6 +#define ATA_PIO2_HOLD 2 +#define ATA_PIO1_SETUP 2 +#define ATA_PIO1_STROBE 11 +#define ATA_PIO1_HOLD 4 +#define ATA_PIO0_SETUP 4 +#define ATA_PIO0_STROBE 19 +#define ATA_PIO0_HOLD 4 + +static int e100_dma_check (ide_drive_t *drive); +static int e100_dma_begin (ide_drive_t *drive); +static int e100_dma_end (ide_drive_t *drive); +static int e100_dma_read (ide_drive_t *drive); +static int e100_dma_write (ide_drive_t *drive); +static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int); +static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int); +static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); +static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); +static int e100_dma_off (ide_drive_t *drive); +static int e100_dma_verbose (ide_drive_t *drive); + + +/* + * good_dma_drives() lists the model names (from "hdparm -i") + * of drives which do not support mword2 DMA but which are + * known to work fine with this interface under Linux. + */ + +const char *good_dma_drives[] = {"Micropolis 2112A", + "CONNER CTMA 4000", + "CONNER CTT8000-A", + NULL}; + +static void tune_e100_ide(ide_drive_t *drive, byte pio) +{ + pio = 4; + /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */ + + /* set pio mode! */ + + switch(pio) { + case 0: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) ); + break; + case 1: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) ); + break; + case 2: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) ); + break; + case 3: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) ); + break; + case 4: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); + break; + } +} + +void __init +init_e100_ide (void) +{ + volatile unsigned int dummy; + int h; + + printk("ide: ETRAX 100LX built-in ATA DMA controller\n"); + + /* first fill in some stuff in the ide_hwifs fields */ + + for(h = 0; h < MAX_HWIFS; h++) { + ide_hwif_t *hwif = &ide_hwifs[h]; + hwif->mmio = 2; + hwif->chipset = ide_etrax100; + hwif->tuneproc = &tune_e100_ide; + hwif->ata_input_data = &e100_ide_input_data; + hwif->ata_output_data = &e100_ide_output_data; + hwif->atapi_input_bytes = &e100_atapi_input_bytes; + hwif->atapi_output_bytes = &e100_atapi_output_bytes; + hwif->ide_dma_check = &e100_dma_check; + hwif->ide_dma_end = &e100_dma_end; + hwif->ide_dma_write = &e100_dma_write; + hwif->ide_dma_read = &e100_dma_read; + hwif->ide_dma_begin = &e100_dma_begin; + hwif->OUTB = &etrax100_ide_outb; + hwif->OUTW = &etrax100_ide_outw; + hwif->OUTBSYNC = &etrax100_ide_outbsync; + hwif->INB = &etrax100_ide_inb; + hwif->INW = &etrax100_ide_inw; + hwif->ide_dma_off_quietly = &e100_dma_off; + hwif->ide_dma_verbose = &e100_dma_verbose; + hwif->sg_table = + kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL); + } + + /* actually reset and configure the etrax100 ide/ata interface */ + + *R_ATA_CTRL_DATA = 0; + *R_ATA_TRANSFER_CNT = 0; + *R_ATA_CONFIG = 0; + + genconfig_shadow = (genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, dma2) & + ~IO_MASK(R_GEN_CONFIG, dma3) & + ~IO_MASK(R_GEN_CONFIG, ata)) | + ( IO_STATE( R_GEN_CONFIG, dma3, ata ) | + IO_STATE( R_GEN_CONFIG, dma2, ata ) | + IO_STATE( R_GEN_CONFIG, ata, select ) ); + + *R_GEN_CONFIG = genconfig_shadow; + + /* pull the chosen /reset-line low */ + +#ifdef CONFIG_ETRAX_IDE_G27_RESET + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0); +#endif +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET + REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0); +#endif +#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0); +#endif +#ifdef CONFIG_ETRAX_IDE_PB7_RESET + port_pb_dir_shadow = port_pb_dir_shadow | + IO_STATE(R_PORT_PB_DIR, dir7, output); + *R_PORT_PB_DIR = port_pb_dir_shadow; + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1); +#endif + + /* wait some */ + + udelay(25); + + /* de-assert bus-reset */ + +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET + REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1); +#endif +#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1); +#endif +#ifdef CONFIG_ETRAX_IDE_G27_RESET + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1); +#endif + + /* make a dummy read to set the ata controller in a proper state */ + dummy = *R_ATA_STATUS_DATA; + + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); + + *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) | + IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) ); + + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/ + + *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); + + printk("ide: waiting %d seconds for drives to regain consciousness\n", + CONFIG_ETRAX_IDE_DELAY); + + h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ); + while(time_before(jiffies, h)) /* nothing */ ; + + /* reset the dma channels we will use */ + + RESET_DMA(ATA_TX_DMA_NBR); + RESET_DMA(ATA_RX_DMA_NBR); + WAIT_DMA(ATA_TX_DMA_NBR); + WAIT_DMA(ATA_RX_DMA_NBR); + +} + +static int e100_dma_off (ide_drive_t *drive) +{ + return 0; +} + +static int e100_dma_verbose (ide_drive_t *drive) +{ + printk(", DMA(mode 2)"); + return 0; +} + +static etrax_dma_descr mydescr; + +/* + * The following routines are mainly used by the ATAPI drivers. + * + * These routines will round up any request for an odd number of bytes, + * so if an odd bytecount is specified, be sure that there's at least one + * extra byte allocated for the buffer. + */ +static void +e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + ide_ioreg_t data_reg = IDE_DATA_REG; + + D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n", + data_reg, buffer, bytecount)); + + if(bytecount & 1) { + printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); + bytecount++; /* to round off */ + } + + /* make sure the DMA channel is available */ + RESET_DMA(ATA_RX_DMA_NBR); + WAIT_DMA(ATA_RX_DMA_NBR); + + /* setup DMA descriptor */ + + mydescr.sw_len = bytecount; + mydescr.ctrl = d_eol; + mydescr.buf = virt_to_phys(buffer); + + /* start the dma channel */ + + *R_DMA_CH3_FIRST = virt_to_phys(&mydescr); + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); + + /* initiate a multi word dma read using PIO handshaking */ + + *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* wait for completion */ + + LED_DISK_READ(1); + WAIT_DMA(ATA_RX_DMA_NBR); + LED_DISK_READ(0); + +#if 0 + /* old polled transfer code + * this should be moved into a new function that can do polled + * transfers if DMA is not available + */ + + /* initiate a multi word read */ + + *R_ATA_TRANSFER_CNT = wcount << 1; + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* svinto has a latency until the busy bit actually is set */ + + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + + /* unit should be busy during multi transfer */ + while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) { + while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav))) + status = *R_ATA_STATUS_DATA; + *ptr++ = (unsigned short)(status & 0xffff); + } +#endif +} + +static void +e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + ide_ioreg_t data_reg = IDE_DATA_REG; + + D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n", + data_reg, buffer, bytecount)); + + if(bytecount & 1) { + printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); + bytecount++; + } + + /* make sure the DMA channel is available */ + RESET_DMA(ATA_TX_DMA_NBR); + WAIT_DMA(ATA_TX_DMA_NBR); + + /* setup DMA descriptor */ + + mydescr.sw_len = bytecount; + mydescr.ctrl = d_eol; + mydescr.buf = virt_to_phys(buffer); + + /* start the dma channel */ + + *R_DMA_CH2_FIRST = virt_to_phys(&mydescr); + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); + + /* initiate a multi word dma write using PIO handshaking */ + + *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* wait for completion */ + + LED_DISK_WRITE(1); + WAIT_DMA(ATA_TX_DMA_NBR); + LED_DISK_WRITE(0); + +#if 0 + /* old polled write code - see comment in input_bytes */ + + /* wait for busy flag */ + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); + + /* initiate a multi word write */ + + *R_ATA_TRANSFER_CNT = bytecount >> 1; + + ctrl = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_WRITE(1); + + /* Etrax will set busy = 1 until the multi pio transfer has finished + * and tr_rdy = 1 after each successful word transfer. + * When the last byte has been transferred Etrax will first set tr_tdy = 1 + * and then busy = 0 (not in the same cycle). If we read busy before it + * has been set to 0 we will think that we should transfer more bytes + * and then tr_rdy would be 0 forever. This is solved by checking busy + * in the inner loop. + */ + + do { + *R_ATA_CTRL_DATA = ctrl | *ptr++; + while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) && + (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))); + } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); + + LED_DISK_WRITE(0); +#endif + +} + +/* + * This is used for most PIO data transfers *from* the IDE interface + */ +static void +e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + e100_atapi_input_bytes(drive, buffer, wcount << 2); +} + +/* + * This is used for most PIO data transfers *to* the IDE interface + */ +static void +e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + e100_atapi_output_bytes(drive, buffer, wcount << 2); +} + +/* we only have one DMA channel on the chip for ATA, so we can keep these statically */ +static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS]; +static unsigned int ata_tot_size; + +/* + * e100_ide_build_dmatable() prepares a dma request. + * Returns 0 if all went okay, returns 1 otherwise. + */ +static int e100_ide_build_dmatable (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct scatterlist* sg; + struct request *rq = HWGROUP(drive)->rq; + unsigned long size, addr; + unsigned int count = 0; + int i = 0; + + sg = hwif->sg_table; + + ata_tot_size = 0; + + if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) { + u8 *virt_addr = rq->buffer; + int sector_count = rq->nr_sectors; + memset(&sg[0], 0, sizeof(*sg)); + sg[0].page = virt_to_page(virt_addr); + sg[0].offset = offset_in_page(virt_addr); + sg[0].length = sector_count * SECTOR_SIZE; + hwif->sg_nents = i = 1; + } + else + { + hwif->sg_nents = i = blk_rq_map_sg(drive->queue, rq, hwif->sg_table); + } + + + while(i) { + /* + * Determine addr and size of next buffer area. We assume that + * individual virtual buffers are always composed linearly in + * physical memory. For example, we assume that any 8kB buffer + * is always composed of two adjacent physical 4kB pages rather + * than two possibly non-adjacent physical 4kB pages. + */ + /* group sequential buffers into one large buffer */ + addr = page_to_phys(sg->page) + sg->offset; + size = sg_dma_len(sg); + while (sg++, --i) { + if ((addr + size) != page_to_phys(sg->page) + sg->offset) + break; + size += sg_dma_len(sg); + } + + /* did we run out of descriptors? */ + + if(count >= MAX_DMA_DESCRS) { + printk("%s: too few DMA descriptors\n", drive->name); + return 1; + } + + /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more + than 65536 words per transfer, so in that case we need to either + 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with + the descriptors, or + 2) simply do the request here, and get dma_intr to only ide_end_request on + those blocks that were actually set-up for transfer. + */ + + if(ata_tot_size + size > 131072) { + printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size); + return 1; + } + + /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle + size > 131072 only one split is necessary */ + + if(size > 65536) { + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ + ata_descrs[count].ctrl = 0; + ata_descrs[count].buf = addr; + ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); + count++; + ata_tot_size += 65536; + /* size and addr should refere to not handled data */ + size -= 65536; + addr += 65536; + } + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + if(size == 65536) { + ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ + } else { + ata_descrs[count].sw_len = size; + } + ata_descrs[count].ctrl = 0; + ata_descrs[count].buf = addr; + ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); + count++; + ata_tot_size += size; + } + + if (count) { + /* set the end-of-list flag on the last descriptor */ + ata_descrs[count - 1].ctrl |= d_eol; + /* return and say all is ok */ + return 0; + } + + printk("%s: empty DMA table?\n", drive->name); + return 1; /* let the PIO routines handle this weirdness */ +} + +static int config_drive_for_dma (ide_drive_t *drive) +{ + const char **list; + struct hd_driveid *id = drive->id; + + if (id && (id->capability & 1)) { + /* Enable DMA on any drive that supports mword2 DMA */ + if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + + /* Consult the list of known "good" drives */ + list = good_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + } + } + return 1; /* DMA not enabled */ +} + +/* + * etrax_dma_intr() is the handler for disk read/write DMA interrupts + */ +static ide_startstop_t etrax_dma_intr (ide_drive_t *drive) +{ + int i, dma_stat; + byte stat; + + LED_DISK_READ(0); + LED_DISK_WRITE(0); + + dma_stat = HWIF(drive)->ide_dma_end(drive); + stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */ + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + if (!dma_stat) { + struct request *rq; + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + DRIVER(drive)->end_request(drive, 1, rq->nr_sectors); + } + return ide_stopped; + } + printk("%s: bad DMA status\n", drive->name); + } + return DRIVER(drive)->error(drive, "dma_intr", stat); +} + +/* + * Functions below initiates/aborts DMA read/write operations on a drive. + * + * The caller is assumed to have selected the drive and programmed the drive's + * sector address using CHS or LBA. All that remains is to prepare for DMA + * and then issue the actual read/write DMA/PIO command to the drive. + * + * For ATAPI devices, we just prepare for DMA and return. The caller should + * then issue the packet command to the drive and call us again with + * ide_dma_begin afterwards. + * + * Returns 0 if all went well. + * Returns 1 if DMA read/write could not be started, in which case + * the caller should revert to PIO for the current request. + */ + +static int e100_dma_check(ide_drive_t *drive) +{ + return config_drive_for_dma (drive); +} + +static int e100_dma_end(ide_drive_t *drive) +{ + /* TODO: check if something went wrong with the DMA */ + return 0; +} + +static int e100_start_dma(ide_drive_t *drive, int atapi, int reading) +{ + if(reading) { + + RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(ATA_RX_DMA_NBR); + + /* set up the Etrax DMA descriptors */ + + if(e100_ide_build_dmatable (drive)) + return 1; + + if(!atapi) { + /* set the irq handler which will finish the request when DMA is done */ + + ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); + + /* issue cmd to drive */ + if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && + (drive->addressing == 1)) { + ide_task_t *args = HWGROUP(drive)->rq->special; + etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing) { + etrax100_ide_outb(WIN_READDMA_EXT, IDE_COMMAND_REG); + } else { + etrax100_ide_outb(WIN_READDMA, IDE_COMMAND_REG); + } + } + + /* begin DMA */ + + /* need to do this before RX DMA due to a chip bug + * it is enough to just flush the part of the cache that + * corresponds to the buffers we start, but since HD transfers + * usually are more than 8 kB, it is easier to optimize for the + * normal case and just flush the entire cache. its the only + * way to be sure! (OB movie quote) + */ + flush_etrax_cache(); + *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs); + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); + + /* initiate a multi word dma read using DMA handshaking */ + + *R_ATA_TRANSFER_CNT = + IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); + + *R_ATA_CTRL_DATA = + IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_READ(1); + + D(printk("dma read of %d bytes.\n", ata_tot_size)); + + } else { + /* writing */ + + RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(ATA_TX_DMA_NBR); + + /* set up the Etrax DMA descriptors */ + + if(e100_ide_build_dmatable (drive)) + return 1; + + if(!atapi) { + /* set the irq handler which will finish the request when DMA is done */ + + ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); + + /* issue cmd to drive */ + if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && + (drive->addressing == 1)) { + ide_task_t *args = HWGROUP(drive)->rq->special; + etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing) { + etrax100_ide_outb(WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + } else { + etrax100_ide_outb(WIN_WRITEDMA, IDE_COMMAND_REG); + } + } + + /* begin DMA */ + + *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs); + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); + + /* initiate a multi word dma write using DMA handshaking */ + + *R_ATA_TRANSFER_CNT = + IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); + + *R_ATA_CTRL_DATA = + IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_WRITE(1); + + D(printk("dma write of %d bytes.\n", ata_tot_size)); + } + return 0; +} + +static int e100_dma_write(ide_drive_t *drive) +{ + e100_read_command = 0; + /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction + * then they call ide_dma_begin after they have issued the appropriate drive command + * themselves to actually start the chipset DMA. so we just return here if we're + * not a diskdrive. + */ + if (drive->media != ide_disk) + return 0; + return e100_start_dma(drive, 0, 0); +} + +static int e100_dma_read(ide_drive_t *drive) +{ + e100_read_command = 1; + /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction + * then they call ide_dma_begin after they have issued the appropriate drive command + * themselves to actually start the chipset DMA. so we just return here if we're + * not a diskdrive. + */ + if (drive->media != ide_disk) + return 0; + return e100_start_dma(drive, 0, 1); +} + +static int e100_dma_begin(ide_drive_t *drive) +{ + /* begin DMA, used by ATAPI devices which want to issue the + * appropriate IDE command themselves. + * + * they have already called ide_dma_read/write to set the + * static reading flag, now they call ide_dma_begin to do + * the real stuff. we tell our code below not to issue + * any IDE commands itself and jump into it. + */ + return e100_start_dma(drive, 1, e100_read_command); +} diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c new file mode 100644 index 000000000..6ded633f8 --- /dev/null +++ b/arch/cris/kernel/crisksyms.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern unsigned long get_cmos_time(void); +extern void __Udiv(void); +extern void __Umod(void); +extern void __Div(void); +extern void __Mod(void); +extern void __ashrdi3(void); +extern void iounmap(void *addr); + +/* Platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(loops_per_usec); + +/* String functions */ +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); + +/* Math functions */ +EXPORT_SYMBOL(__Udiv); +EXPORT_SYMBOL(__Umod); +EXPORT_SYMBOL(__Div); +EXPORT_SYMBOL(__Mod); +EXPORT_SYMBOL(__ashrdi3); + +/* Memory functions */ +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +/* Semaphore functions */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); + +/* Export shadow registers for the CPU I/O pins */ +EXPORT_SYMBOL(genconfig_shadow); +EXPORT_SYMBOL(port_pa_data_shadow); +EXPORT_SYMBOL(port_pa_dir_shadow); +EXPORT_SYMBOL(port_pb_data_shadow); +EXPORT_SYMBOL(port_pb_dir_shadow); +EXPORT_SYMBOL(port_pb_config_shadow); +EXPORT_SYMBOL(port_g_data_shadow); + +/* Userspace access functions */ +EXPORT_SYMBOL(__copy_user_zeroing); +EXPORT_SYMBOL(__copy_user); + +/* Cache flush functions */ +EXPORT_SYMBOL(flush_etrax_cache); +EXPORT_SYMBOL(prepare_rx_descriptor); + +#undef memcpy +#undef memset +extern void * memset(void *, int, __kernel_size_t); +extern void * memcpy(void *, const void *, __kernel_size_t); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); + +#ifdef CONFIG_ETRAX_FAST_TIMER +/* Fast timer functions */ +EXPORT_SYMBOL(fast_timer_list); +EXPORT_SYMBOL(start_one_shot_timer); +EXPORT_SYMBOL(del_fast_timer); +EXPORT_SYMBOL(schedule_usleep); +#endif + diff --git a/arch/i386/defconfig b/arch/i386/defconfig index c2a9ab0aa..7257696c7 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -18,8 +18,11 @@ CONFIG_STANDALONE=y # CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_HOTPLUG=y # CONFIG_IKCONFIG is not set @@ -30,6 +33,7 @@ CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -88,6 +92,7 @@ CONFIG_X86_USE_PPRO_CHECKSUM=y # CONFIG_HPET_EMULATE_RTC is not set CONFIG_SMP=y CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y @@ -200,7 +205,7 @@ CONFIG_BINFMT_MISC=y # # Generic Driver Options # -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=m # # Memory Technology Devices (MTD) @@ -259,7 +264,6 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -307,6 +311,7 @@ CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set # CONFIG_IDE_CHIPSETS is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set @@ -332,7 +337,6 @@ CONFIG_CHR_DEV_SG=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_REPORT_LUNS=y # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set @@ -354,6 +358,7 @@ CONFIG_SCSI_REPORT_LUNS=y # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +CONFIG_SCSI_DPT_I2O=m # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_MEGARAID is not set @@ -361,7 +366,9 @@ CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=y # CONFIG_SCSI_SATA_PROMISE is not set +CONFIG_SCSI_SATA_SX4=m # CONFIG_SCSI_SATA_SIL is not set +CONFIG_SCSI_SATA_SIS=m # CONFIG_SCSI_SATA_VIA is not set # CONFIG_SCSI_SATA_VITESSE is not set # CONFIG_SCSI_BUSLOGIC is not set @@ -380,6 +387,9 @@ CONFIG_SCSI_ATA_PIIX=y # CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C8XX_2 is not set +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set @@ -484,8 +494,6 @@ CONFIG_IP_MULTICAST=y # # CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -539,13 +547,17 @@ CONFIG_IP_NF_TARGET_TCPMSS=y CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m # # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -566,18 +578,23 @@ CONFIG_IP_NF_ARP_MANGLE=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + # # Ethernet (10 or 100Mbit) # @@ -619,7 +636,6 @@ CONFIG_8139TOO_PIO=y # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set -CONFIG_8139_RXBUF_IDX=2 # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -637,7 +653,6 @@ CONFIG_8139_RXBUF_IDX=2 # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set @@ -645,47 +660,31 @@ CONFIG_8139_RXBUF_IDX=2 # Ethernet (10000 Mbit) # # CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # ISDN subsystem @@ -803,6 +802,7 @@ CONFIG_AGP=y # CONFIG_AGP_AMD is not set # CONFIG_AGP_AMD64 is not set CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=m # CONFIG_AGP_NVIDIA is not set # CONFIG_AGP_SIS is not set # CONFIG_AGP_SWORKS is not set @@ -978,6 +978,7 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_OHCI_HCD is not set CONFIG_USB_UHCI_HCD=y @@ -1012,6 +1013,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +CONFIG_USB_EGALAX=m # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -1061,6 +1063,8 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGETSERVO=m # CONFIG_USB_TEST is not set # @@ -1110,6 +1114,7 @@ CONFIG_VFAT_FS=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -1152,7 +1157,6 @@ CONFIG_SUNRPC=y # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -1217,6 +1221,7 @@ CONFIG_OPROFILE=y CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_FRAME_POINTER is not set +CONFIG_4KSTACKS=y CONFIG_X86_FIND_SMP_CONFIG=y CONFIG_X86_MPPARSE=y @@ -1234,8 +1239,10 @@ CONFIG_X86_MPPARSE=y # Library routines # CONFIG_CRC32=y +CONFIG_LIBCRC32C=m CONFIG_X86_SMP=y CONFIG_X86_HT=y CONFIG_X86_BIOS_REBOOT=y CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_STD_RESOURCES=y CONFIG_PC=y diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c index 3305a84b6..82f7c0220 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c @@ -252,11 +252,10 @@ unsigned int speedstep_detect_processor (void) * specific. * M-P4-Ms may have either ebx=0xe or 0xf [see above] * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf] - * So, how to distinguish all those processors with - * ebx=0xf? I don't know. Sort them out, and wait - * for someone to complain. + * also, M-P4M HTs have ebx=0x8, too + * For now, they are distinguished by the model_id string */ - if (ebx == 0x0e) + if ((ebx == 0x0e) || (strstr(c->x86_model_id,"Mobile Intel(R) Pentium(R) 4") != NULL)) return SPEEDSTEP_PROCESSOR_P4M; break; default: @@ -321,9 +320,7 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor); unsigned int speedstep_get_freqs(unsigned int processor, unsigned int *low_speed, unsigned int *high_speed, - void (*set_state) (unsigned int state, - unsigned int notify) - ) + void (*set_state) (unsigned int state)) { unsigned int prev_speed; unsigned int ret = 0; @@ -340,7 +337,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, local_irq_save(flags); /* switch to low state */ - set_state(SPEEDSTEP_LOW, 0); + set_state(SPEEDSTEP_LOW); *low_speed = speedstep_get_processor_frequency(processor); if (!*low_speed) { ret = -EIO; @@ -348,7 +345,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, } /* switch to high state */ - set_state(SPEEDSTEP_HIGH, 0); + set_state(SPEEDSTEP_HIGH); *high_speed = speedstep_get_processor_frequency(processor); if (!*high_speed) { ret = -EIO; @@ -362,7 +359,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, /* switch to previous state, if necessary */ if (*high_speed != prev_speed) - set_state(SPEEDSTEP_LOW, 0); + set_state(SPEEDSTEP_LOW); out: local_irq_restore(flags); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h index 851926d61..261a2c9b7 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h @@ -44,4 +44,4 @@ extern unsigned int speedstep_get_processor_frequency(unsigned int processor); extern unsigned int speedstep_get_freqs(unsigned int processor, unsigned int *low_speed, unsigned int *high_speed, - void (*set_state) (unsigned int state, unsigned int notify)); + void (*set_state) (unsigned int state)); diff --git a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c index 9f80757d1..34f1f3d1c 100644 --- a/arch/i386/kernel/timers/timer_cyclone.c +++ b/arch/i386/kernel/timers/timer_cyclone.c @@ -17,6 +17,7 @@ #include #include #include +#include "io_ports.h" extern spinlock_t i8253_lock; @@ -62,6 +63,17 @@ static void mark_offset_cyclone(void) count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; + + /* + * VIA686a test code... reset the latch if count > max + 1 + * from timer_pit.c - cjb + */ + if (count > LATCH) { + outb_p(0x34, PIT_MODE); + outb_p(LATCH & 0xff, PIT_CH0); + outb(LATCH >> 8, PIT_CH0); + count = LATCH - 1; + } spin_unlock(&i8253_lock); /* lost tick compensation */ diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c index 70db26443..784576c53 100644 --- a/arch/i386/mach-es7000/es7000plat.c +++ b/arch/i386/mach-es7000/es7000plat.c @@ -50,7 +50,6 @@ struct mip_reg *mip_reg; struct mip_reg *host_reg; int mip_port; unsigned long mip_addr, host_addr; -extern int (*platform_rename_gsi)(); static int __init es7000_rename_gsi(int ioapic, int gsi) @@ -134,7 +133,6 @@ parse_unisys_oem (char *oemptr, int oem_entries) } if (success < 2) { - printk("\nNo ES7000 found.\n"); es7000_plat = 0; } else { printk("\nEnabling ES7000 specific features...\n"); diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c new file mode 100644 index 000000000..48d3ec372 --- /dev/null +++ b/arch/i386/mach-generic/es7000.c @@ -0,0 +1,28 @@ +/* + * APIC driver for the Unisys ES7000 chipset. + */ +#define APIC_DEFINITION 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __init int probe_es7000(void) +{ + /* probed later in mptable/ACPI hooks */ + return 0; +} + +struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000); diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig new file mode 100644 index 000000000..5744b59f1 --- /dev/null +++ b/arch/ia64/configs/sim_defconfig @@ -0,0 +1,535 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +# CONFIG_STANDALONE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_HOTPLUG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN2 is not set +CONFIG_IA64_HP_SIM=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +# CONFIG_IA64_PAGE_SIZE_16KB is not set +CONFIG_IA64_PAGE_SIZE_64KB=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set +# CONFIG_VIRTUAL_MEM_MAP is not set +# CONFIG_IA64_CYCLONE is not set +CONFIG_FORCE_MAX_ZONEORDER=18 +CONFIG_SMP=y +CONFIG_NR_CPUS=64 +CONFIG_PREEMPT=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +# CONFIG_PERFMON is not set +CONFIG_IA64_PALINFO=m + +# +# Firmware Drivers +# +CONFIG_EFI_VARS=y +# CONFIG_SMBIOS is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y + +# +# Power management and ACPI +# + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_UNIX is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# HP Simulator drivers +# +CONFIG_HP_SIMETH=y +CONFIG_HP_SIMSERIAL=y +CONFIG_HP_SIMSERIAL_CONSOLE=y +CONFIG_HP_SIMSCSI=y + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_DISABLE_VHPT is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_DEBUG_INFO=y +CONFIG_SYSVIPC_COMPAT=y + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff --git a/arch/ia64/dig/topology.c b/arch/ia64/dig/topology.c new file mode 100644 index 000000000..8dc31378b --- /dev/null +++ b/arch/ia64/dig/topology.c @@ -0,0 +1,43 @@ +/* + * arch/ia64/dig/topology.c + * Popuate driverfs with topology information. + * Derived entirely from i386/mach-default.c + * Intel Corporation - Ashok Raj + */ +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(struct ia64_cpu, cpu_devices); + +/* + * First Pass: simply borrowed code for now. Later should hook into + * hotplug notification for node/cpu/memory as applicable + */ + +static int arch_register_cpu(int num) +{ + struct node *parent = NULL; + +#ifdef CONFIG_NUMA + //parent = &node_devices[cpu_to_node(num)].node; +#endif + + return register_cpu(&per_cpu(cpu_devices,num).cpu, num, parent); +} + +static int __init topology_init(void) +{ + int i; + + for_each_cpu(i) { + arch_register_cpu(i); + } + return 0; +} + +subsys_initcall(topology_init); diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index 36e8a24ff..a4dba3648 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -91,16 +91,18 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc) cmp.geu p6,p7=r19,r17 // (syscall > 0 && syscall < 1024+NR_syscalls)? ;; (p6) ld8 r18=[r18] - mov r29=psr // read psr (12 cyc load latency) + mov r21=ar.fpsr add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry ;; (p6) mov b7=r18 (p6) tbit.z p8,p0=r18,0 (p8) br.dptk.many b7 +(p6) rsm psr.i mov r27=ar.rsc - mov r21=ar.fpsr mov r26=ar.pfs + ;; + mov r29=psr // read psr (12 cyc load latency) /* * brl.cond doesn't work as intended because the linker would convert this branch * into a branch to a PLT. Perhaps there will be a way to avoid this with some diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 5c45718a9..57912212b 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -195,11 +195,10 @@ SECTIONS .data : AT(ADDR(.data) - LOAD_OFFSET) { *(.data) *(.data1) *(.gnu.linkonce.d*) CONSTRUCTORS } - . = ALIGN(16); - __gp = . + 0x200000; /* gp must be 16-byte aligned for exc. table */ - + . = ALIGN(16); /* gp must be 16-byte aligned for exc. table */ .got : AT(ADDR(.got) - LOAD_OFFSET) { *(.got.plt) *(.got) } + __gp = ADDR(.got) + 0x200000; /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 218de3efc..1902c3c2e 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -6,7 +6,7 @@ obj-y := io.o lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ - checksum.o clear_page.o csum_partial_copy.o copy_page.o \ + bitop.o checksum.o clear_page.o csum_partial_copy.o copy_page.o \ clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ flush.o ip_fast_csum.o do_csum.o \ memset.o strlen.o swiotlb.o diff --git a/arch/ia64/lib/bitop.c b/arch/ia64/lib/bitop.c new file mode 100644 index 000000000..1c6ee49fd --- /dev/null +++ b/arch/ia64/lib/bitop.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +/* + * Find next zero bit in a bitmap reasonably efficiently.. + */ + +int __find_next_zero_bit (void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (64-offset); + if (size < 64) + goto found_first; + if (~tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; +found_first: + tmp |= ~0UL << size; + if (tmp == ~0UL) /* any bits zero? */ + return result + size; /* nope */ +found_middle: + return result + ffz(tmp); +} +EXPORT_SYMBOL(__find_next_zero_bit); + +/* + * Find next bit in a bitmap reasonably efficiently.. + */ +int __find_next_bit(const void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp &= ~0UL << offset; + if (size < 64) + goto found_first; + if (tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if ((tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; + found_first: + tmp &= ~0UL >> (64-size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ + found_middle: + return result + __ffs(tmp); +} +EXPORT_SYMBOL(__find_next_bit); diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 662674017..fdcc71a09 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -323,8 +323,10 @@ pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus) struct pci_controller *controller = PCI_CONTROLLER(dev); struct pci_window *window; int i, j; + int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \ + PCI_ROM_RESOURCE : PCI_NUM_RESOURCES; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { + for (i = 0; i < limit; i++) { if (!dev->resource[i].start) continue; diff --git a/arch/ia64/sn/io/machvec/iomv.c b/arch/ia64/sn/io/machvec/iomv.c index df17cc049..10ee752ea 100644 --- a/arch/ia64/sn/io/machvec/iomv.c +++ b/arch/ia64/sn/io/machvec/iomv.c @@ -71,6 +71,6 @@ sn_mmiob (void) { while ((((volatile unsigned long) (*pda->pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) - udelay(1); + cpu_relax(); } EXPORT_SYMBOL(sn_mmiob); diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c index f8147fec7..a4d7c5615 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved. */ #include @@ -1615,6 +1615,46 @@ pcibr_piomap_probe(pcibr_piomap_t piomap, off_t offset, int len, void *valp) piomap->bp_kvaddr + offset, len, valp); } +static uint64_t +pcibr_disable_mst_timeout(pcibr_soft_t pcibr_soft) +{ + uint64_t old_enable; + uint64_t new_enable; + uint64_t intr_bits; + + intr_bits = PIC_ISR_PCI_MST_TIMEOUT + | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; + old_enable = pcireg_intr_enable_get(pcibr_soft); + pcireg_intr_enable_bit_clr(pcibr_soft, intr_bits); + new_enable = pcireg_intr_enable_get(pcibr_soft); + + if (old_enable == new_enable) { + return 0; /* was already disabled */ + } else { + return 1; + } +} + +static int +pcibr_enable_mst_timeout(pcibr_soft_t pcibr_soft) +{ + uint64_t old_enable; + uint64_t new_enable; + uint64_t intr_bits; + + intr_bits = PIC_ISR_PCI_MST_TIMEOUT + | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; + old_enable = pcireg_intr_enable_get(pcibr_soft); + pcireg_intr_enable_bit_set(pcibr_soft, intr_bits); + new_enable = pcireg_intr_enable_get(pcibr_soft); + + if (old_enable == new_enable) { + return 0; /* was alread enabled */ + } else { + return 1; + } +} + /* * pcibr_probe_slot: read a config space word * while trapping any errors; return zero if @@ -1628,7 +1668,7 @@ pcibr_probe_work(pcibr_soft_t pcibr_soft, int len, void *valp) { - int rv; + int rv, changed; /* * Sanity checks ... @@ -1642,15 +1682,19 @@ pcibr_probe_work(pcibr_soft_t pcibr_soft, return -1; /* invalid alignment */ } + changed = pcibr_disable_mst_timeout(pcibr_soft); + rv = snia_badaddr_val((void *)addr, len, valp); /* Clear the int_view register incase it was set */ pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_MULTI_CLR); + if (changed) { + pcibr_enable_mst_timeout(pcibr_soft); + } return (rv ? 1 : 0); /* return 1 for snia_badaddr_val error, 0 if ok */ } - void pcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c new file mode 100644 index 000000000..26744b317 --- /dev/null +++ b/arch/mips/au1000/common/cputable.c @@ -0,0 +1,56 @@ +/* + * arch/mips/au1000/common/cputable.c + * + * Copyright (C) 2004 Dan Malek (dan@embeddededge.com) + * Copied from PowerPC and updated for Alchemy Au1xxx processors. + * + * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * 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 +#include +#include + +struct cpu_spec* cur_cpu_spec[NR_CPUS]; + +/* With some thought, we can probably use the mask to reduce the + * size of the table. + */ +struct cpu_spec cpu_specs[] = { + { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0 }, + { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0 }, + { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0 }, + { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1 }, + { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1 }, + { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1 }, + { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1 }, + { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1 }, + { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1 }, + { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1 }, + { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1 }, + { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 }, + { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 }, + { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 }, + { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 }, +}; + +void +set_cpuspec(void) +{ + struct cpu_spec *sp; + u32 prid; + + prid = read_c0_prid(); + sp = cpu_specs; + while ((prid & sp->prid_mask) != sp->prid_value) + sp++; + cur_cpu_spec[0] = sp; +} diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c new file mode 100644 index 000000000..ccfd5fe5a --- /dev/null +++ b/arch/parisc/kernel/unwind.c @@ -0,0 +1,295 @@ +/* + * Kernel unwinding support + * + * (c) 2002-2004 Randolph Chung + * + * Derived partially from the IA64 implementation. The PA-RISC + * Runtime Architecture Document is also a useful reference to + * understand what is happening here + */ + +/* + * J. David Anglin writes: + * + * "You have to adjust the current sp to that at the begining of the function. + * There can be up to two stack additions to allocate the frame in the + * prologue. Similar things happen in the epilogue. In the presence of + * interrupts, you have to be concerned about where you are in the function + * and what stack adjustments have taken place." + * + * For now these cases are not handled, but they should be! + */ + +#include +#include +#include +#include + +#include + +#include + +/* #define DEBUG 1 */ +#ifdef DEBUG +#define dbg(x...) printk(x) +#else +#define dbg(x...) +#endif + +extern const struct unwind_table_entry __start___unwind[]; +extern const struct unwind_table_entry __stop___unwind[]; + +static spinlock_t unwind_lock; +/* + * the kernel unwind block is not dynamically allocated so that + * we can call unwind_init as early in the bootup process as + * possible (before the slab allocator is initialized) + */ +static struct unwind_table kernel_unwind_table; +static struct unwind_table *unwind_tables, *unwind_tables_end; + + +static inline const struct unwind_table_entry * +find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr) +{ + const struct unwind_table_entry *e = 0; + unsigned long lo, hi, mid; + + addr -= table->base_addr; + + for (lo = 0, hi = table->length; lo < hi; ) + { + mid = (lo + hi) / 2; + e = &table->table[mid]; + if (addr < e->region_start) + hi = mid; + else if (addr > e->region_end) + lo = mid + 1; + else + break; + } + + return e; +} + +static inline const struct unwind_table_entry * +find_unwind_entry(unsigned long addr) +{ + struct unwind_table *table = unwind_tables; + const struct unwind_table_entry *e = NULL; + + if (addr >= kernel_unwind_table.start && + addr <= kernel_unwind_table.end) + e = find_unwind_entry_in_table(&kernel_unwind_table, addr); + else + for (; table; table = table->next) + { + if (addr >= table->start && + addr <= table->end) + e = find_unwind_entry_in_table(table, addr); + if (e) + break; + } + + return e; +} + +static void +unwind_table_init(struct unwind_table *table, const char *name, + unsigned long base_addr, unsigned long gp, + const void *table_start, const void *table_end) +{ + const struct unwind_table_entry *start = table_start; + const struct unwind_table_entry *end = table_end - 1; + + table->name = name; + table->base_addr = base_addr; + table->gp = gp; + table->start = base_addr + start->region_start; + table->end = base_addr + end->region_end; + table->table = (struct unwind_table_entry *)table_start; + table->length = end - start; + table->next = NULL; +} + +void * +unwind_table_add(const char *name, unsigned long base_addr, + unsigned long gp, + const void *start, const void *end) +{ + struct unwind_table *table; + unsigned long flags; + + table = kmalloc(sizeof(struct unwind_table), GFP_USER); + if (table == NULL) + return 0; + unwind_table_init(table, name, base_addr, gp, start, end); + spin_lock_irqsave(&unwind_lock, flags); + if (unwind_tables) + { + unwind_tables_end->next = table; + unwind_tables_end = table; + } + else + { + unwind_tables = unwind_tables_end = table; + } + spin_unlock_irqrestore(&unwind_lock, flags); + + return table; +} + +/* Called from setup_arch to import the kernel unwind info */ +static int unwind_init(void) +{ + long start, stop; + register unsigned long gp __asm__ ("r27"); + + start = (long)&__start___unwind[0]; + stop = (long)&__stop___unwind[0]; + + printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", + start, stop, + (stop - start) / sizeof(struct unwind_table_entry)); + + unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START, + gp, + &__start___unwind[0], &__stop___unwind[0]); +#if 0 + { + int i; + for (i = 0; i < 10; i++) + { + printk("region 0x%x-0x%x\n", + __start___unwind[i].region_start, + __start___unwind[i].region_end); + } + } +#endif + return 0; +} + +static void unwind_frame_regs(struct unwind_frame_info *info) +{ + const struct unwind_table_entry *e; + unsigned long npc; + unsigned int insn; + long frame_size = 0; + int looking_for_rp, rpoffset = 0; + + e = find_unwind_entry(info->ip); + if (!e) { + unsigned long sp; + extern char _stext[], _etext[]; + + dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip); + + /* Since we are doing the unwinding blind, we don't know if + we are adjusting the stack correctly or extracting the rp + correctly. The rp is checked to see if it belongs to the + kernel text section, if not we assume we don't have a + correct stack frame and we continue to unwind the stack. + This is not quite correct, and will fail for loadable + modules. */ + sp = info->sp & ~63; + do { + info->prev_sp = sp - 64; + + /* FIXME: what happens if we unwind too far so that + sp no longer falls in a mapped kernel page? */ +#ifndef __LP64__ + info->prev_ip = *(unsigned long *)(info->prev_sp - 20); +#else + info->prev_ip = *(unsigned long *)(info->prev_sp - 16); +#endif + + sp = info->prev_sp; + } while (info->prev_ip < (unsigned long)_stext || + info->prev_ip > (unsigned long)_etext); + } else { + + dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n", + e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size); + + looking_for_rp = e->Save_RP; + + for (npc = e->region_start; + (frame_size < (e->Total_frame_size << 3) || looking_for_rp) && + npc < info->ip; + npc += 4) { + + insn = *(unsigned int *)npc; + + if ((insn & 0xffffc000) == 0x37de0000 || + (insn & 0xffe00000) == 0x6fc00000) { + /* ldo X(sp), sp, or stwm X,D(sp) */ + frame_size += (insn & 0x1 ? -1 << 13 : 0) | + ((insn & 0x3fff) >> 1); + } else if ((insn & 0xffe00008) == 0x7ec00008) { + /* std,ma X,D(sp) */ + frame_size += (insn & 0x1 ? -1 << 13 : 0) | + (((insn >> 4) & 0x3ff) << 3); + } else if (insn == 0x6bc23fd9) { + /* stw rp,-20(sp) */ + rpoffset = 20; + looking_for_rp = 0; + } else if (insn == 0x0fc212c1) { + /* std rp,-16(sr0,sp) */ + rpoffset = 16; + looking_for_rp = 0; + } + } + + info->prev_sp = info->sp - frame_size; + if (rpoffset) + info->prev_ip = *(unsigned long *)(info->prev_sp - rpoffset); + } +} + +void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, + struct pt_regs *regs) +{ + memset(info, 0, sizeof(struct unwind_frame_info)); + info->t = t; + info->sp = regs->ksp; + info->ip = regs->kpc; + + dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", (int)t->pid, info->sp, info->ip); +} + +void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t) +{ + struct pt_regs *regs = &t->thread.regs; + unwind_frame_init(info, t, regs); +} + +int unwind_once(struct unwind_frame_info *next_frame) +{ + unwind_frame_regs(next_frame); + + if (next_frame->prev_sp == 0 || + next_frame->prev_ip == 0) + return -1; + + next_frame->sp = next_frame->prev_sp; + next_frame->ip = next_frame->prev_ip; + next_frame->prev_sp = 0; + next_frame->prev_ip = 0; + + dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip); + + return 0; +} + +int unwind_to_user(struct unwind_frame_info *info) +{ + int ret; + + do { + ret = unwind_once(info); + } while (!ret && !(info->ip & 3)); + + return ret; +} + +module_init(unwind_init); diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index 226214c66..d9df49ceb 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -158,12 +158,21 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr); #define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) #define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) +#ifdef CONFIG_SBC82xx +/* rx is clk9, tx is clk10 + */ +#define PC_F1RXCLK ((uint)0x00000100) +#define PC_F1TXCLK ((uint)0x00000200) +#define CMX1_CLK_ROUTE ((uint)0x25000000) +#define CMX1_CLK_MASK ((uint)0xff000000) +#else /* CLK12 is receive, CLK11 is transmit. These are board specific. */ #define PC_F1RXCLK ((uint)0x00000800) #define PC_F1TXCLK ((uint)0x00000400) #define CMX1_CLK_ROUTE ((uint)0x3e000000) #define CMX1_CLK_MASK ((uint)0xff000000) +#endif /* !CONFIG_SBC82xx */ /* I/O Pin assignment for FCC2. I don't yet know the best way to do this, * but there is little variation among the choices. @@ -288,6 +297,8 @@ struct fcc_enet_private { ushort skb_cur; ushort skb_dirty; + atomic_t n_pkts; /* Number of packets in tx ring */ + /* CPM dual port RAM relative addresses. */ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ @@ -347,6 +358,7 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; volatile cbd_t *bdp; + int idx; if (!cep->link) { /* Link is down or autonegotiation is in progress. */ @@ -379,13 +391,24 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bdp->cbd_datlen = skb->len; bdp->cbd_bufaddr = __pa(skb->data); + spin_lock_irq(&cep->lock); + /* Save skb pointer. */ - cep->tx_skbuff[cep->skb_cur] = skb; + idx = cep->skb_cur & TX_RING_MOD_MASK; + if (cep->tx_skbuff[idx]) { + /* This should never happen (any more). + Leave the sanity check in for now... */ + printk(KERN_ERR "EEP. cep->tx_skbuff[%d] is %p not NULL in %s\n", + idx, cep->tx_skbuff[idx], __func__); + printk(KERN_ERR "Expect to lose %d bytes of sock space", + cep->tx_skbuff[idx]->truesize); + } + cep->tx_skbuff[idx] = skb; cep->stats.tx_bytes += skb->len; - cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + cep->skb_cur++; - spin_lock_irq(&cep->lock); + atomic_inc(&cep->n_pkts); /* Send it on its way. Tell CPM its ready, interrupt when done, * its the last BD of the frame, and to put the CRC on the end. @@ -404,9 +427,13 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) else bdp++; - if (bdp->cbd_sc & BD_ENET_TX_READY) { - netif_stop_queue(dev); + + /* If the tx_ring is full, stop the queue */ + if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); cep->tx_full = 1; + } } cep->cur_tx = (cbd_t *)bdp; @@ -460,6 +487,7 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) volatile cbd_t *bdp; ushort int_events; int must_restart; + int idx; cep = (struct fcc_enet_private *)dev->priv; @@ -522,8 +550,12 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) cep->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ - dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); - cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + idx = cep->skb_dirty & TX_RING_MOD_MASK; + dev_kfree_skb_irq(cep->tx_skbuff[idx]); + cep->tx_skbuff[idx] = NULL; + cep->skb_dirty++; + + atomic_dec(&cep->n_pkts); /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) @@ -1594,11 +1626,21 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev, */ eap = (unsigned char *)&(ep->fen_paddrh); for (i=5; i>=0; i--) { +#ifdef CONFIG_SBC82xx + if (i == 5) { + /* bd->bi_enetaddr holds the SCC0 address; the FCC + devices count up from there */ + dev->dev_addr[i] = bd->bi_enetaddr[i] & ~3; + dev->dev_addr[i] += 1 + fip->fc_fccnum; + *eap++ = dev->dev_addr[i]; + } +#else if (i == 3) { dev->dev_addr[i] = bd->bi_enetaddr[i]; dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); *eap++ = dev->dev_addr[i]; } +#endif else { *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; } @@ -1683,6 +1725,7 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev, while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; + atomic_set(&cep->n_pkts, 0); } /* Let 'er rip. diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c new file mode 100644 index 000000000..c859f1127 --- /dev/null +++ b/arch/ppc/kernel/dma-mapping.c @@ -0,0 +1,439 @@ +/* + * PowerPC version derived from arch/arm/mm/consistent.c + * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) + * + * Copyright (C) 2000 Russell King + * + * Consistent memory allocators. Used for DMA devices that want to + * share uncached memory with the processor core. The function return + * is the virtual address and 'dma_handle' is the physical address. + * Mostly stolen from the ARM port, with some changes for PowerPC. + * -- Dan + * + * Reorganized to get rid of the arch-specific consistent_* functions + * and provide non-coherent implementations for the DMA API. -Matt + * + * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent() + * implementation. This is pulled straight from ARM and barely + * modified. -Matt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int map_page(unsigned long va, phys_addr_t pa, int flags); + +#include + +/* + * This address range defaults to a value that is safe for all + * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It + * can be further configured for specific applications under + * the "Advanced Setup" menu. -Matt + */ +#define CONSISTENT_BASE (CONFIG_CONSISTENT_START) +#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE) +#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) + +/* + * This is the page table (2MB) covering uncached, DMA consistent allocations + */ +static pte_t *consistent_pte; +static spinlock_t consistent_lock = SPIN_LOCK_UNLOCKED; + +/* + * VM region handling support. + * + * This should become something generic, handling VM region allocations for + * vmalloc and similar (ioremap, module space, etc). + * + * I envisage vmalloc()'s supporting vm_struct becoming: + * + * struct vm_struct { + * struct vm_region region; + * unsigned long flags; + * struct page **pages; + * unsigned int nr_pages; + * unsigned long phys_addr; + * }; + * + * get_vm_area() would then call vm_region_alloc with an appropriate + * struct vm_region head (eg): + * + * struct vm_region vmalloc_head = { + * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list), + * .vm_start = VMALLOC_START, + * .vm_end = VMALLOC_END, + * }; + * + * However, vmalloc_head.vm_start is variable (typically, it is dependent on + * the amount of RAM found at boot time.) I would imagine that get_vm_area() + * would have to initialise this each time prior to calling vm_region_alloc(). + */ +struct vm_region { + struct list_head vm_list; + unsigned long vm_start; + unsigned long vm_end; +}; + +static struct vm_region consistent_head = { + .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), + .vm_start = CONSISTENT_BASE, + .vm_end = CONSISTENT_END, +}; + +static struct vm_region * +vm_region_alloc(struct vm_region *head, size_t size, int gfp) +{ + unsigned long addr = head->vm_start, end = head->vm_end - size; + unsigned long flags; + struct vm_region *c, *new; + + new = kmalloc(sizeof(struct vm_region), gfp); + if (!new) + goto out; + + spin_lock_irqsave(&consistent_lock, flags); + + list_for_each_entry(c, &head->vm_list, vm_list) { + if ((addr + size) < addr) + goto nospc; + if ((addr + size) <= c->vm_start) + goto found; + addr = c->vm_end; + if (addr > end) + goto nospc; + } + + found: + /* + * Insert this entry _before_ the one we found. + */ + list_add_tail(&new->vm_list, &c->vm_list); + new->vm_start = addr; + new->vm_end = addr + size; + + spin_unlock_irqrestore(&consistent_lock, flags); + return new; + + nospc: + spin_unlock_irqrestore(&consistent_lock, flags); + kfree(new); + out: + return NULL; +} + +static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) +{ + struct vm_region *c; + + list_for_each_entry(c, &head->vm_list, vm_list) { + if (c->vm_start == addr) + goto out; + } + c = NULL; + out: + return c; +} + +/* + * Allocate DMA-coherent memory space and return both the kernel remapped + * virtual and bus address for that space. + */ +void * +__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp) +{ + struct page *page; + struct vm_region *c; + unsigned long order; + u64 mask = 0x00ffffff, limit; /* ISA default */ + + if (!consistent_pte) { + printk(KERN_ERR "%s: not initialised\n", __func__); + dump_stack(); + return NULL; + } + + size = PAGE_ALIGN(size); + limit = (mask + 1) & ~mask; + if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { + printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", + size, mask); + return NULL; + } + + order = get_order(size); + + if (mask != 0xffffffff) + gfp |= GFP_DMA; + + page = alloc_pages(gfp, order); + if (!page) + goto no_page; + + /* + * Invalidate any data that might be lurking in the + * kernel direct-mapped region for device DMA. + */ + { + unsigned long kaddr = (unsigned long)page_address(page); + memset(page_address(page), 0, size); + flush_dcache_range(kaddr, kaddr + size); + } + + /* + * Allocate a virtual address in the consistent mapping region. + */ + c = vm_region_alloc(&consistent_head, size, + gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); + if (c) { + pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); + struct page *end = page + (1 << order); + + /* + * Set the "dma handle" + */ + *handle = page_to_bus(page); + + do { + BUG_ON(!pte_none(*pte)); + + set_page_count(page, 1); + SetPageReserved(page); + set_pte(pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL))); + page++; + pte++; + } while (size -= PAGE_SIZE); + + /* + * Free the otherwise unused pages. + */ + while (page < end) { + set_page_count(page, 1); + __free_page(page); + page++; + } + + return (void *)c->vm_start; + } + + if (page) + __free_pages(page, order); + no_page: + return NULL; +} + +/* + * free a page as defined by the above mapping. + */ +void __dma_free_coherent(size_t size, void *vaddr) +{ + struct vm_region *c; + unsigned long flags; + pte_t *ptep; + + size = PAGE_ALIGN(size); + + spin_lock_irqsave(&consistent_lock, flags); + + c = vm_region_find(&consistent_head, (unsigned long)vaddr); + if (!c) + goto no_area; + + if ((c->vm_end - c->vm_start) != size) { + printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + __func__, c->vm_end - c->vm_start, size); + dump_stack(); + size = c->vm_end - c->vm_start; + } + + ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start); + do { + pte_t pte = ptep_get_and_clear(ptep); + unsigned long pfn; + + ptep++; + + if (!pte_none(pte) && pte_present(pte)) { + pfn = pte_pfn(pte); + + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + ClearPageReserved(page); + + __free_page(page); + continue; + } + } + + printk(KERN_CRIT "%s: bad page in kernel page table\n", + __func__); + } while (size -= PAGE_SIZE); + + flush_tlb_kernel_range(c->vm_start, c->vm_end); + + list_del(&c->vm_list); + + spin_unlock_irqrestore(&consistent_lock, flags); + + kfree(c); + return; + + no_area: + spin_unlock_irqrestore(&consistent_lock, flags); + printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", + __func__, vaddr); + dump_stack(); +} +EXPORT_SYMBOL(dma_free_coherent); + +/* + * Initialise the consistent memory allocation. + */ +static int __init dma_alloc_init(void) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int ret = 0; + + spin_lock(&init_mm.page_table_lock); + + do { + pgd = pgd_offset(&init_mm, CONSISTENT_BASE); + pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); + if (!pmd) { + printk(KERN_ERR "%s: no pmd tables\n", __func__); + ret = -ENOMEM; + break; + } + WARN_ON(!pmd_none(*pmd)); + + pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE); + if (!pte) { + printk(KERN_ERR "%s: no pte tables\n", __func__); + ret = -ENOMEM; + break; + } + + consistent_pte = pte; + } while (0); + + spin_unlock(&init_mm.page_table_lock); + + return ret; +} + +core_initcall(dma_alloc_init); + +/* + * make an area consistent. + */ +void __dma_sync(void *vaddr, size_t size, int direction) +{ + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + + switch (direction) { + case DMA_NONE: + BUG(); + case DMA_FROM_DEVICE: /* invalidate only */ + invalidate_dcache_range(start, end); + break; + case DMA_TO_DEVICE: /* writeback only */ + clean_dcache_range(start, end); + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + flush_dcache_range(start, end); + break; + } +} + +#ifdef CONFIG_HIGHMEM +/* + * __dma_sync_page() implementation for systems using highmem. + * In this case, each page of a buffer must be kmapped/kunmapped + * in order to have a virtual address for __dma_sync(). This must + * not sleep so kmap_atmomic()/kunmap_atomic() are used. + * + * Note: yes, it is possible and correct to have a buffer extend + * beyond the first page. + */ +static inline void __dma_sync_page_highmem(struct page *page, + unsigned long offset, size_t size, int direction) +{ + size_t seg_size = min((size_t)PAGE_SIZE, size) - offset; + size_t cur_size = seg_size; + unsigned long flags, start, seg_offset = offset; + int nr_segs = PAGE_ALIGN(size + (PAGE_SIZE - offset))/PAGE_SIZE; + int seg_nr = 0; + + local_irq_save(flags); + + do { + start = (unsigned long)kmap_atomic(page + seg_nr, + KM_PPC_SYNC_PAGE) + seg_offset; + + /* Sync this buffer segment */ + __dma_sync((void *)start, seg_size, direction); + kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); + seg_nr++; + + /* Calculate next buffer segment size */ + seg_size = min((size_t)PAGE_SIZE, size - cur_size); + + /* Add the segment size to our running total */ + cur_size += seg_size; + seg_offset = 0; + } while (seg_nr < nr_segs); + + local_irq_restore(flags); +} +#endif /* CONFIG_HIGHMEM */ + +/* + * __dma_sync_page makes memory consistent. identical to __dma_sync, but + * takes a struct page instead of a virtual address + */ +void __dma_sync_page(struct page *page, unsigned long offset, + size_t size, int direction) +{ +#ifdef CONFIG_HIGHMEM + __dma_sync_page_highmem(page, offset, size, direction); +#else + unsigned long start = (unsigned long)page_address(page) + offset; + __dma_sync((void *)start, size, direction); +#endif +} diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index c1df60395..cc3b36c0d 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -304,8 +304,10 @@ void disable_irq_nosync(unsigned int irq) void disable_irq(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; disable_irq_nosync(irq); - synchronize_irq(irq); + if (desc->action) + synchronize_irq(irq); } /** diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 5b4965534..f095fcd74 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -128,7 +128,7 @@ pcibios_fixup_resources(struct pci_dev *dev) struct resource *res = dev->resource + i; if (!res->flags) continue; - if (!res->start || res->end == 0xffffffff) { + if (res->end == 0xffffffff) { DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n", pci_name(dev), i, res->start, res->end); res->end -= res->start; @@ -347,6 +347,8 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i) return -1; } res = bus->resource[i]; + if (res == NULL) + return -1; pr = NULL; for (j = 0; j < 4; j++) { struct resource *r = parent->resource[j]; @@ -659,11 +661,11 @@ make_one_node_map(struct device_node* node, u8 pci_bus) return; bus_range = (int *) get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - node->full_name); - return; - } - pci_to_OF_bus_map[pci_bus] = bus_range[0]; + printk(KERN_WARNING "Can't get bus-range for %s, " + "assuming it starts at 0\n", node->full_name); + pci_to_OF_bus_map[pci_bus] = 0; + } else + pci_to_OF_bus_map[pci_bus] = bus_range[0]; for (node=node->child; node != 0;node = node->sibling) { struct pci_dev* dev; @@ -1073,6 +1075,8 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga) u16 w; struct resource res; + if (bus->resource[0] == NULL) + return; res = *(bus->resource[0]); DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name); @@ -1168,7 +1172,8 @@ do_fixup_p2p_level(struct pci_bus *bus) int has_vga = 0; for (parent_io=0; parent_io<4; parent_io++) - if (bus->resource[parent_io]->flags & IORESOURCE_IO) + if (bus->resource[parent_io] + && bus->resource[parent_io]->flags & IORESOURCE_IO) break; if (parent_io >= 4) return; diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 7d2f3a5cd..ad7808fa6 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -101,7 +101,7 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf, { unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; int n = 0; -#ifdef CONFIG_PPC_STD_MMU +#if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE) unsigned int kptes = 0, uptes = 0; PTE *ptr; #endif /* CONFIG_PPC_STD_MMU */ @@ -135,6 +135,7 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf, goto return_string; } +#ifndef CONFIG_PPC64BRIDGE for (ptr = Hash; ptr < Hash_end; ptr++) { unsigned int mctx, vsid; @@ -148,6 +149,7 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf, else uptes++; } +#endif n += sprintf( buffer + n, "PTE Hash Table Information\n" @@ -155,16 +157,20 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf, "Buckets\t\t: %lu\n" "Address\t\t: %08lx\n" "Entries\t\t: %lu\n" +#ifndef CONFIG_PPC64BRIDGE "User ptes\t: %u\n" "Kernel ptes\t: %u\n" - "Percent full\t: %lu%%\n", - (unsigned long)(Hash_size>>10), + "Percent full\t: %lu%%\n" +#endif + , (unsigned long)(Hash_size>>10), (Hash_size/(sizeof(PTE)*8)), (unsigned long)Hash, - Hash_size/sizeof(PTE), - uptes, + Hash_size/sizeof(PTE) +#ifndef CONFIG_PPC64BRIDGE + , uptes, kptes, ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) +#endif ); n += sprintf( buffer + n, diff --git a/arch/ppc/kernel/vecemu.c b/arch/ppc/kernel/vecemu.c new file mode 100644 index 000000000..1430ef592 --- /dev/null +++ b/arch/ppc/kernel/vecemu.c @@ -0,0 +1,346 @@ +/* + * Routines to emulate some Altivec/VMX instructions, specifically + * those that can trap when given denormalized operands in Java mode. + */ +#include +#include +#include +#include +#include +#include + +/* Functions in vector.S */ +extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b); +extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b); +extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); +extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); +extern void vrefp(vector128 *dst, vector128 *src); +extern void vrsqrtefp(vector128 *dst, vector128 *src); +extern void vexptep(vector128 *dst, vector128 *src); + +static unsigned int exp2s[8] = { + 0x800000, + 0x8b95c2, + 0x9837f0, + 0xa5fed7, + 0xb504f3, + 0xc5672a, + 0xd744fd, + 0xeac0c7 +}; + +/* + * Computes an estimate of 2^x. The `s' argument is the 32-bit + * single-precision floating-point representation of x. + */ +static unsigned int eexp2(unsigned int s) +{ + int exp, pwr; + unsigned int mant, frac; + + /* extract exponent field from input */ + exp = ((s >> 23) & 0xff) - 127; + if (exp > 7) { + /* check for NaN input */ + if (exp == 128 && (s & 0x7fffff) != 0) + return s | 0x400000; /* return QNaN */ + /* 2^-big = 0, 2^+big = +Inf */ + return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */ + } + if (exp < -23) + return 0x3f800000; /* 1.0 */ + + /* convert to fixed point integer in 9.23 representation */ + pwr = (s & 0x7fffff) | 0x800000; + if (exp > 0) + pwr <<= exp; + else + pwr >>= -exp; + if (s & 0x80000000) + pwr = -pwr; + + /* extract integer part, which becomes exponent part of result */ + exp = (pwr >> 23) + 126; + if (exp >= 254) + return 0x7f800000; + if (exp < -23) + return 0; + + /* table lookup on top 3 bits of fraction to get mantissa */ + mant = exp2s[(pwr >> 20) & 7]; + + /* linear interpolation using remaining 20 bits of fraction */ + asm("mulhwu %0,%1,%2" : "=r" (frac) + : "r" (pwr << 12), "r" (0x172b83ff)); + asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant)); + mant += frac; + + if (exp >= 0) + return mant + (exp << 23); + + /* denormalized result */ + exp = -exp; + mant += 1 << (exp - 1); + return mant >> exp; +} + +/* + * Computes an estimate of log_2(x). The `s' argument is the 32-bit + * single-precision floating-point representation of x. + */ +static unsigned int elog2(unsigned int s) +{ + int exp, mant, lz, frac; + + exp = s & 0x7f800000; + mant = s & 0x7fffff; + if (exp == 0x7f800000) { /* Inf or NaN */ + if (mant != 0) + s |= 0x400000; /* turn NaN into QNaN */ + return s; + } + if ((exp | mant) == 0) /* +0 or -0 */ + return 0xff800000; /* return -Inf */ + + if (exp == 0) { + /* denormalized */ + asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant)); + mant <<= lz - 8; + exp = (-118 - lz) << 23; + } else { + mant |= 0x800000; + exp -= 127 << 23; + } + + if (mant >= 0xb504f3) { /* 2^0.5 * 2^23 */ + exp |= 0x400000; /* 0.5 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xb504f334)); /* 2^-0.5 * 2^32 */ + } + if (mant >= 0x9837f0) { /* 2^0.25 * 2^23 */ + exp |= 0x200000; /* 0.25 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xd744fccb)); /* 2^-0.25 * 2^32 */ + } + if (mant >= 0x8b95c2) { /* 2^0.125 * 2^23 */ + exp |= 0x100000; /* 0.125 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xeac0c6e8)); /* 2^-0.125 * 2^32 */ + } + if (mant > 0x800000) { /* 1.0 * 2^23 */ + /* calculate (mant - 1) * 1.381097463 */ + /* 1.381097463 == 0.125 / (2^0.125 - 1) */ + asm("mulhwu %0,%1,%2" : "=r" (frac) + : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a)); + exp += frac; + } + s = exp & 0x80000000; + if (exp != 0) { + if (s) + exp = -exp; + asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp)); + lz = 8 - lz; + if (lz > 0) + exp >>= lz; + else if (lz < 0) + exp <<= -lz; + s += ((lz + 126) << 23) + exp; + } + return s; +} + +#define VSCR_SAT 1 + +static int ctsxs(unsigned int x, int scale, unsigned int *vscrp) +{ + int exp, mant; + + exp = (x >> 23) & 0xff; + mant = x & 0x7fffff; + if (exp == 255 && mant != 0) + return 0; /* NaN -> 0 */ + exp = exp - 127 + scale; + if (exp < 0) + return 0; /* round towards zero */ + if (exp >= 31) { + /* saturate, unless the result would be -2^31 */ + if (x + (scale << 23) != 0xcf000000) + *vscrp |= VSCR_SAT; + return (x & 0x80000000)? 0x80000000: 0x7fffffff; + } + mant |= 0x800000; + mant = (mant << 7) >> (30 - exp); + return (x & 0x80000000)? -mant: mant; +} + +static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp) +{ + int exp; + unsigned int mant; + + exp = (x >> 23) & 0xff; + mant = x & 0x7fffff; + if (exp == 255 && mant != 0) + return 0; /* NaN -> 0 */ + exp = exp - 127 + scale; + if (exp < 0) + return 0; /* round towards zero */ + if (x & 0x80000000) { + /* negative => saturate to 0 */ + *vscrp |= VSCR_SAT; + return 0; + } + if (exp >= 32) { + /* saturate */ + *vscrp |= VSCR_SAT; + return 0xffffffff; + } + mant |= 0x800000; + mant = (mant << 8) >> (31 - exp); + return mant; +} + +/* Round to floating integer, towards 0 */ +static unsigned int rfiz(unsigned int x) +{ + int exp; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if (exp < 0) + return x & 0x80000000; /* |x| < 1.0 rounds to 0 */ + return x & ~(0x7fffff >> exp); +} + +/* Round to floating integer, towards +/- Inf */ +static unsigned int rfii(unsigned int x) +{ + int exp, mask; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if ((x & 0x7fffffff) == 0) + return x; /* +/-0 -> +/-0 */ + if (exp < 0) + /* 0 < |x| < 1.0 rounds to +/- 1.0 */ + return (x & 0x80000000) | 0x3f800000; + mask = 0x7fffff >> exp; + /* mantissa overflows into exponent - that's OK, + it can't overflow into the sign bit */ + return (x + mask) & ~mask; +} + +/* Round to floating integer, to nearest */ +static unsigned int rfin(unsigned int x) +{ + int exp, half; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if (exp < -1) + return x & 0x80000000; /* |x| < 0.5 -> +/-0 */ + if (exp == -1) + /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */ + return (x & 0x80000000) | 0x3f800000; + half = 0x400000 >> exp; + /* add 0.5 to the magnitude and chop off the fraction bits */ + return (x + half) & ~(0x7fffff >> exp); +} + +int +emulate_altivec(struct pt_regs *regs) +{ + unsigned int instr, i; + unsigned int va, vb, vc, vd; + vector128 *vrs; + + if (get_user(instr, (unsigned int *) regs->nip)) + return -EFAULT; + if ((instr >> 26) != 4) + return -EINVAL; /* not an altivec instruction */ + vd = (instr >> 21) & 0x1f; + va = (instr >> 16) & 0x1f; + vb = (instr >> 11) & 0x1f; + vc = (instr >> 6) & 0x1f; + + vrs = current->thread.vr; + switch (instr & 0x3f) { + case 10: + switch (vc) { + case 0: /* vaddfp */ + vaddfp(&vrs[vd], &vrs[va], &vrs[vb]); + break; + case 1: /* vsubfp */ + vsubfp(&vrs[vd], &vrs[va], &vrs[vb]); + break; + case 4: /* vrefp */ + vrefp(&vrs[vd], &vrs[vb]); + break; + case 5: /* vrsqrtefp */ + vrsqrtefp(&vrs[vd], &vrs[vb]); + break; + case 6: /* vexptefp */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = eexp2(vrs[vb].u[i]); + break; + case 7: /* vlogefp */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = elog2(vrs[vb].u[i]); + break; + case 8: /* vrfin */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = rfin(vrs[vb].u[i]); + break; + case 9: /* vrfiz */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = rfiz(vrs[vb].u[i]); + break; + case 10: /* vrfip */ + for (i = 0; i < 4; ++i) { + u32 x = vrs[vb].u[i]; + x = (x & 0x80000000)? rfiz(x): rfii(x); + vrs[vd].u[i] = x; + } + break; + case 11: /* vrfim */ + for (i = 0; i < 4; ++i) { + u32 x = vrs[vb].u[i]; + x = (x & 0x80000000)? rfii(x): rfiz(x); + vrs[vd].u[i] = x; + } + break; + case 14: /* vctuxs */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va, + ¤t->thread.vscr.u[3]); + break; + case 15: /* vctsxs */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va, + ¤t->thread.vscr.u[3]); + break; + default: + return -EINVAL; + } + break; + case 46: /* vmaddfp */ + vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); + break; + case 47: /* vnmsubfp */ + vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/arch/ppc/kernel/vector.S b/arch/ppc/kernel/vector.S new file mode 100644 index 000000000..d8fe6b5fb --- /dev/null +++ b/arch/ppc/kernel/vector.S @@ -0,0 +1,217 @@ +#include +#include + +/* + * The routines below are in assembler so we can closely control the + * usage of floating-point registers. These routines must be called + * with preempt disabled. + */ + .data +fpzero: + .long 0 +fpone: + .long 0x3f800000 /* 1.0 in single-precision FP */ +fphalf: + .long 0x3f000000 /* 0.5 in single-precision FP */ + + .text +/* + * Internal routine to enable floating point and set FPSCR to 0. + * Don't call it from C; it doesn't use the normal calling convention. + */ +fpenable: + mfmsr r10 + ori r11,r10,MSR_FP + mtmsr r11 + isync + stfd fr0,24(r1) + stfd fr1,16(r1) + stfd fr31,8(r1) + lis r11,fpzero@ha + mffs fr31 + lfs fr1,fpzero@l(r11) + mtfsf 0xff,fr1 + blr + +fpdisable: + mtfsf 0xff,fr31 + lfd fr31,8(r1) + lfd fr1,16(r1) + lfd fr0,24(r1) + mtmsr r10 + isync + blr + +/* + * Vector add, floating point. + */ + .globl vaddfp +vaddfp: + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fadds fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + bl fpdisable + lwz r0,36(r1) + mtlr r0 + addi r1,r1,32 + blr + +/* + * Vector subtract, floating point. + */ + .globl vsubfp +vsubfp: + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fsubs fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + bl fpdisable + lwz r0,36(r1) + mtlr r0 + addi r1,r1,32 + blr + +/* + * Vector multiply and add, floating point. + */ + .globl vmaddfp +vmaddfp: + stwu r1,-48(r1) + mflr r0 + stw r0,52(r1) + bl fpenable + stfd fr2,32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fmadds fr0,fr0,fr1,fr2 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,32(r1) + bl fpdisable + lwz r0,52(r1) + mtlr r0 + addi r1,r1,48 + blr + +/* + * Vector negative multiply and subtract, floating point. + */ + .globl vnmsubfp +vnmsubfp: + stwu r1,-48(r1) + mflr r0 + stw r0,52(r1) + bl fpenable + stfd fr2,32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fnmsubs fr0,fr0,fr1,fr2 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,32(r1) + bl fpdisable + lwz r0,52(r1) + mtlr r0 + addi r1,r1,48 + blr + +/* + * Vector reciprocal estimate. We just compute 1.0/x. + * r3 -> destination, r4 -> source. + */ + .globl vrefp +vrefp: + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + bl fpenable + lis r9,fpone@ha + li r0,4 + lfs fr1,fpone@l(r9) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + fdivs fr0,fr1,fr0 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + bl fpdisable + lwz r0,36(r1) + mtlr r0 + addi r1,r1,32 + blr + +/* + * Vector reciprocal square-root estimate, floating point. + * We use the frsqrte instruction for the initial estimate followed + * by 2 iterations of Newton-Raphson to get sufficient accuracy. + * r3 -> destination, r4 -> source. + */ + .globl vrsqrtefp +vrsqrtefp: + stwu r1,-48(r1) + mflr r0 + stw r0,52(r1) + bl fpenable + stfd fr2,32(r1) + stfd fr3,40(r1) + stfd fr4,48(r1) + stfd fr5,56(r1) + lis r9,fpone@ha + lis r8,fphalf@ha + li r0,4 + lfs fr4,fpone@l(r9) + lfs fr5,fphalf@l(r8) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + frsqrte fr1,fr0 /* r = frsqrte(s) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + stfsx fr1,r3,r6 + addi r6,r6,4 + bdnz 1b + lfd fr5,56(r1) + lfd fr4,48(r1) + lfd fr3,40(r1) + lfd fr2,32(r1) + bl fpdisable + lwz r0,36(r1) + mtlr r0 + addi r1,r1,32 + blr diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index 1f85f3ef2..0eaffa9b5 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,7 @@ * since they may inhibit forward progress by other CPUs in getting * a lock. */ -unsigned long __spin_trylock(volatile unsigned long *lock) +static inline unsigned long __spin_trylock(volatile unsigned long *lock) { unsigned long ret; @@ -62,6 +63,7 @@ void _raw_spin_lock(spinlock_t *lock) lock->owner_pc = (unsigned long)__builtin_return_address(0); lock->owner_cpu = cpu; } +EXPORT_SYMBOL(_raw_spin_lock); int _raw_spin_trylock(spinlock_t *lock) { @@ -71,6 +73,7 @@ int _raw_spin_trylock(spinlock_t *lock) lock->owner_pc = (unsigned long)__builtin_return_address(0); return 1; } +EXPORT_SYMBOL(_raw_spin_trylock); void _raw_spin_unlock(spinlock_t *lp) { @@ -86,6 +89,7 @@ void _raw_spin_unlock(spinlock_t *lp) wmb(); lp->lock = 0; } +EXPORT_SYMBOL(_raw_spin_unlock); /* @@ -119,6 +123,7 @@ again: } wmb(); } +EXPORT_SYMBOL(_raw_read_lock); void _raw_read_unlock(rwlock_t *rw) { @@ -129,6 +134,7 @@ void _raw_read_unlock(rwlock_t *rw) wmb(); atomic_dec((atomic_t *) &(rw)->lock); } +EXPORT_SYMBOL(_raw_read_unlock); void _raw_write_lock(rwlock_t *rw) { @@ -169,6 +175,22 @@ again: } wmb(); } +EXPORT_SYMBOL(_raw_write_lock); + +int _raw_write_trylock(rwlock_t *rw) +{ + if (test_and_set_bit(31, &(rw)->lock)) /* someone has a write lock */ + return 0; + + if ((rw)->lock & ~(1<<31)) { /* someone has a read lock */ + /* clear our write lock and wait for reads to go away */ + clear_bit(31,&(rw)->lock); + return 0; + } + wmb(); + return 1; +} +EXPORT_SYMBOL(_raw_write_trylock); void _raw_write_unlock(rwlock_t *rw) { @@ -179,5 +201,6 @@ void _raw_write_unlock(rwlock_t *rw) wmb(); clear_bit(31,&(rw)->lock); } +EXPORT_SYMBOL(_raw_write_unlock); #endif diff --git a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c index 3bf70f65f..34605ba4a 100644 --- a/arch/ppc/mm/tlb.c +++ b/arch/ppc/mm/tlb.c @@ -66,6 +66,17 @@ void flush_hash_one_pte(pte_t *ptep) flush_hash_pages(mm->context, addr, ptephys, 1); } +/* + * Called by ptep_set_access_flags, must flush on CPUs for which the + * DSI handler can't just "fixup" the TLB on a write fault + */ +void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr) +{ + if (Hash != 0) + return; + _tlbie(addr); +} + /* * Called at the end of a mmu_gather operation to make sure the * TLB flush is completely done. diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c new file mode 100644 index 000000000..3678abf86 --- /dev/null +++ b/arch/ppc/platforms/4xx/bubinga.c @@ -0,0 +1,263 @@ +/* + * Support for IBM PPC 405EP evaluation board (Bubinga). + * + * Author: SAW (IBM), derived from walnut.c. + * Maintained by MontaVista Software + * + * 2003 (c) MontaVista Softare Inc. 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +extern bd_t __res; + +void *bubinga_rtc_base; + +/* Some IRQs unique to the board + * Used by the generic 405 PCI setup functions in ppc4xx_pci.c + */ +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */ + {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */ + {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */ + {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */ + }; + + const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +}; + +/* The serial clock for the chip is an internal clock determined by + * different clock speeds/dividers. + * Calculate the proper input baud rate and setup the serial driver. + */ +static void __init +bubinga_early_serial_map(void) +{ + u32 uart_div; + int uart_clock; + struct uart_port port; + + /* Calculate the serial clock input frequency + * + * The base baud is the PLL OUTA (provided in the board info + * structure) divided by the external UART Divisor, divided + * by 16. + */ + uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV); + uart_clock = __res.bi_pllouta_freq / uart_div; + + /* Setup serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = (void*)ACTING_UART0_IO_BASE; + port.irq = ACTING_UART0_INT; + port.uartclk = uart_clock; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + + port.membase = (void*)ACTING_UART1_IO_BASE; + port.irq = ACTING_UART1_INT; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } +} + +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ + + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + * The following code is simplified by assuming that the bootrom + * has been well behaved in following this mapping. + */ + +#ifdef DEBUG + int i; + + printk("ioremap PCLIO_BASE = 0x%x\n", pcip); + printk("PCI bridge regs before fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif + + /* added for IBM boot rom version 1.15 bios bar changes -AK */ + + /* Disable region first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000001); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + out_le32((void *) &(pcip->ptm2la), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ + +#ifdef DEBUG + printk("PCI bridge regs after fixup \n"); + for (i = 0; i <= 3; i++) { + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila))); + printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha))); + } + printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms))); + printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la))); + printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms))); + printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la))); + +#endif +} + +void __init +bubinga_setup_arch(void) +{ + ppc4xx_setup_arch(); + + ibm_ocp_set_emac(0, 1); + + bubinga_early_serial_map(); + + /* RTC step for the evb405ep */ + bubinga_rtc_base = (void *) BUBINGA_RTC_VADDR; + TODC_INIT(TODC_TYPE_DS1743, bubinga_rtc_base, bubinga_rtc_base, + bubinga_rtc_base, 8); + /* Identify the system */ + printk("IBM Bubinga port (MontaVista Software, Inc. )\n"); +} + +void __init +bubinga_map_io(void) +{ + ppc4xx_map_io(); + io_block_mapping(BUBINGA_RTC_VADDR, + BUBINGA_RTC_PADDR, BUBINGA_RTC_SIZE, _PAGE_IO); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + ppc4xx_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = bubinga_setup_arch; + ppc_md.setup_io_mappings = bubinga_map_io; + +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; +#endif +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = bubinga_early_serial_map; +#endif +} + diff --git a/arch/ppc/platforms/4xx/bubinga.h b/arch/ppc/platforms/4xx/bubinga.h new file mode 100644 index 000000000..b1df856f8 --- /dev/null +++ b/arch/ppc/platforms/4xx/bubinga.h @@ -0,0 +1,69 @@ +/* + * Support for IBM PPC 405EP evaluation board (Bubinga). + * + * Author: SAW (IBM), derived from walnut.h. + * Maintained by MontaVista Software + * + * 2003 (c) MontaVista Softare Inc. 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. + */ + +#ifdef __KERNEL__ +#ifndef __BUBINGA_H__ +#define __BUBINGA_H__ + +/* 405EP */ +#include + +#ifndef __ASSEMBLY__ +/* + * Data structure defining board information maintained by the boot + * ROM on IBM's evaluation board. An effort has been made to + * keep the field names consistent with the 8xx 'bd_t' board info + * structures. + */ + +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[2][6]; /* Local Ethernet MAC address */ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + + +/* Memory map for the Bubinga board. + * Generic 4xx plus RTC. + */ + +extern void *bubinga_rtc_base; +#define BUBINGA_RTC_PADDR ((uint)0xf0000000) +#define BUBINGA_RTC_VADDR BUBINGA_RTC_PADDR +#define BUBINGA_RTC_SIZE ((uint)8*1024) + +/* The UART clock is based off an internal clock - + * define BASE_BAUD based on the internal clock and divider(s). + * Since BASE_BAUD must be a constant, we will initialize it + * using clock/divider values which OpenBIOS initializes + * for typical configurations at various CPU speeds. + * The base baud is calculated as (FWDA / EXT UART DIV / 16) + */ +#define BASE_BAUD 0 + +#define BUBINGA_FPGA_BASE 0xF0300000 + +#define PPC4xx_MACHINE_NAME "IBM Bubinga" + +#endif /* !__ASSEMBLY__ */ +#endif /* __BUBINGA_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ibm405ep.c b/arch/ppc/platforms/4xx/ibm405ep.c new file mode 100644 index 000000000..fb48e8254 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405ep.c @@ -0,0 +1,134 @@ +/* + * arch/ppc/platforms/ibm405ep.c + * + * Support for IBM PPC 405EP processors. + * + * Author: SAW (IBM), derived from ibmnp405l.c. + * Maintained by MontaVista Software + * + * 2003 (c) MontaVista Softare Inc. 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 + +static struct ocp_func_mal_data ibm405ep_mal0_def = { + .num_tx_chans = 4, /* Number of TX channels */ + .num_rx_chans = 2, /* Number of RX channels */ + .txeob_irq = 11, /* TX End Of Buffer IRQ */ + .rxeob_irq = 12, /* RX End Of Buffer IRQ */ + .txde_irq = 13, /* TX Descriptor Error IRQ */ + .rxde_irq = 14, /* RX Descriptor Error IRQ */ + .serr_irq = 10, /* MAL System Error IRQ */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_emac_data ibm405ep_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = 0, /* MDIO via EMAC0 */ + .tah_idx = -1, /* No TAH */ +}; + +static struct ocp_func_emac_data ibm405ep_emac1_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* ZMII device index */ + .zmii_mux = 0, /* ZMII input of this EMAC */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 1, /* MAL rx channel number */ + .mal_tx_chan = 2, /* MAL tx channel number */ + .wol_irq = 9, /* WOL interrupt number */ + .mdio_idx = 0, /* MDIO via EMAC0 */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_iic_data ibm405ep_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_OPB, + .index = 0, + .paddr = 0xEF600000, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = 0xEF600500, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ibm405ep_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = 0xEF600700, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0 + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_mal0_def, + .show = &ocp_show_mal_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = EMAC0_BASE, + .irq = 15, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_emac0_def, + .show = &ocp_show_emac_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 1, + .paddr = 0xEF600900, + .irq = 17, + .pm = OCP_CPM_NA, + .additions = &ibm405ep_emac1_def, + .show = &ocp_show_emac_data + }, + { .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/4xx/ibm405ep.h b/arch/ppc/platforms/4xx/ibm405ep.h new file mode 100644 index 000000000..e051e3fe8 --- /dev/null +++ b/arch/ppc/platforms/4xx/ibm405ep.h @@ -0,0 +1,148 @@ +/* + * arch/ppc/platforms/4xx/ibm405ep.h + * + * IBM PPC 405EP processor defines. + * + * Author: SAW (IBM), derived from ibm405gp.h. + * Maintained by MontaVista Software + * + * 2003 (c) MontaVista Softare Inc. 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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBM405EP_H__ +#define __ASM_IBM405EP_H__ + +#include + +/* ibm405.h at bottom of this file */ + +/* PCI + * PCI Bridge config reg definitions + * see 17-19 of manual + */ + +#define PPC405_PCI_CONFIG_ADDR 0xeec00000 +#define PPC405_PCI_CONFIG_DATA 0xeec00004 + +#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */ + /* setbat */ +#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */ +#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */ +#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */ + +#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */ +#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */ +#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */ +#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */ + +#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE + +#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE) +#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR +#define PPC4xx_PCI_IO_SIZE ((uint)64*1024) +#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR) +#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR +#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024) +#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000) +#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR +#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024) +#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000) +#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR +#define PPC4xx_ONB_IO_SIZE ((uint)4*1024) + +/* serial port defines */ +#define RS_TABLE_SIZE 2 + +#define UART0_INT 0 +#define UART1_INT 1 + +#define PCIL0_BASE 0xEF400000 +#define UART0_IO_BASE 0xEF600300 +#define UART1_IO_BASE 0xEF600400 +#define EMAC0_BASE 0xEF600800 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i] + +#if defined(CONFIG_UART0_TTYS0) +#define ACTING_UART0_IO_BASE UART0_IO_BASE +#define ACTING_UART1_IO_BASE UART1_IO_BASE +#define ACTING_UART0_INT UART0_INT +#define ACTING_UART1_INT UART1_INT +#else +#define ACTING_UART0_IO_BASE UART1_IO_BASE +#define ACTING_UART1_IO_BASE UART0_IO_BASE +#define ACTING_UART0_INT UART1_INT +#define ACTING_UART1_INT UART0_INT +#endif + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, ACTING_UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)ACTING_UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_DEBUG_IO_BASE ACTING_UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +/* DCR defines */ +#define DCRN_CPMSR_BASE 0x0BA +#define DCRN_CPMFR_BASE 0x0B9 + +#define DCRN_CPC0_PLLMR0_BASE 0x0F0 +#define DCRN_CPC0_BOOT_BASE 0x0F1 +#define DCRN_CPC0_CR1_BASE 0x0F2 +#define DCRN_CPC0_EPRCSR_BASE 0x0F3 +#define DCRN_CPC0_PLLMR1_BASE 0x0F4 +#define DCRN_CPC0_UCR_BASE 0x0F5 +#define DCRN_CPC0_UCR_U0DIV 0x07F +#define DCRN_CPC0_SRR_BASE 0x0F6 +#define DCRN_CPC0_JTAGID_BASE 0x0F7 +#define DCRN_CPC0_SPARE_BASE 0x0F8 +#define DCRN_CPC0_PCI_BASE 0x0F9 + + +#define IBM_CPM_GPT 0x80000000 /* GPT interface */ +#define IBM_CPM_PCI 0x40000000 /* PCI bridge */ +#define IBM_CPM_UIC 0x00010000 /* Universal Int Controller */ +#define IBM_CPM_CPU 0x00008000 /* processor core */ +#define IBM_CPM_EBC 0x00002000 /* EBC controller */ +#define IBM_CPM_SDRAM0 0x00004000 /* SDRAM memory controller */ +#define IBM_CPM_GPIO0 0x00001000 /* General Purpose IO */ +#define IBM_CPM_TMRCLK 0x00000400 /* CPU timers */ +#define IBM_CPM_PLB 0x00000100 /* PLB bus arbiter */ +#define IBM_CPM_OPB 0x00000080 /* PLB to OPB bridge */ +#define IBM_CPM_DMA 0x00000040 /* DMA controller */ +#define IBM_CPM_IIC0 0x00000010 /* IIC interface */ +#define IBM_CPM_UART1 0x00000002 /* serial port 0 */ +#define IBM_CPM_UART0 0x00000001 /* serial port 1 */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \ + | IBM_CPM_OPB | IBM_CPM_EBC \ + | IBM_CPM_SDRAM0 | IBM_CPM_PLB \ + | IBM_CPM_UIC | IBM_CPM_TMRCLK) +#define DCRN_DMA0_BASE 0x100 +#define DCRN_DMA1_BASE 0x108 +#define DCRN_DMA2_BASE 0x110 +#define DCRN_DMA3_BASE 0x118 +#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */ +#define DCRN_DMASR_BASE 0x120 +#define DCRN_EBC_BASE 0x012 +#define DCRN_DCP0_BASE 0x014 +#define DCRN_MAL_BASE 0x180 +#define DCRN_OCM0_BASE 0x018 +#define DCRN_PLB0_BASE 0x084 +#define DCRN_PLLMR_BASE 0x0B0 +#define DCRN_POB0_BASE 0x0A0 +#define DCRN_SDRAM0_BASE 0x010 +#define DCRN_UIC0_BASE 0x0C0 +#define UIC0 DCRN_UIC0_BASE + +#include + +#endif /* __ASM_IBM405EP_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index 31f2d3067..6f0c42645 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_PPLUS) += pplus.o obj-$(CONFIG_PRPMC750) += prpmc750.o obj-$(CONFIG_PRPMC800) += prpmc800.o obj-$(CONFIG_SANDPOINT) += sandpoint.o +obj-$(CONFIG_SBC82xx) += sbc82xx.o obj-$(CONFIG_SPRUCE) += spruce.o ifeq ($(CONFIG_SMP),y) diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c new file mode 100644 index 000000000..0da699d3b --- /dev/null +++ b/arch/ppc/platforms/sbc82xx.c @@ -0,0 +1,113 @@ +/* + * arch/ppc/platforms/sbc82xx.c + * + * SBC82XX platform support + * + * Author: Guy Streeter + * + * Derived from: est8260_setup.c by Allen Curtis, ONZ + * + * Copyright 2004 Red Hat, Inc. + * + * 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 +#include +#include +#include +#include + +static void (*callback_setup_arch)(void); + +extern unsigned char __res[sizeof(bd_t)]; + +extern void m8260_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7); + +extern void (*late_time_init)(void); + +static int +sbc82xx_show_cpuinfo(struct seq_file *m) +{ + bd_t *binfo = (bd_t *)__res; + + seq_printf(m, "vendor\t\t: Wind River\n" + "machine\t\t: SBC PowerQUICC II\n" + "\n" + "mem size\t\t: 0x%08lx\n" + "console baud\t\t: %ld\n" + "\n", + binfo->bi_memsize, + binfo->bi_baudrate); + return 0; +} + +static void __init +sbc82xx_setup_arch(void) +{ + printk("SBC PowerQUICC II Port\n"); + callback_setup_arch(); +} + +TODC_ALLOC(); + +/* + * Timer init happens before mem_init but after paging init, so we cannot + * directly use ioremap() at that time. + * late_time_init() is call after paging init. + */ +#ifdef CONFIG_GEN_RTC +static void sbc82xx_time_init(void) +{ + volatile memctl8260_t *mc = &immr->im_memctl; + TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0); + + /* Set up CS11 for RTC chip */ + mc->memc_br11=0; + mc->memc_or11=0xffff0836; + mc->memc_br11=0x80000801; + + todc_info->nvram_data = + (unsigned int)ioremap(todc_info->nvram_data, 0x2000); + BUG_ON(!todc_info->nvram_data); + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + todc_time_init(); +} +#endif /* CONFIG_GEN_RTC */ + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* Generic 8260 platform initialization */ + m8260_init(r3, r4, r5, r6, r7); + + /* u-boot may be using one of the FCC Ethernet devices. + Use the MAC address to the SCC. */ + __res[offsetof(bd_t, bi_enetaddr[5])] &= ~3; + + /* Anything special for this platform */ + ppc_md.show_cpuinfo = sbc82xx_show_cpuinfo; + + callback_setup_arch = ppc_md.setup_arch; + ppc_md.setup_arch = sbc82xx_setup_arch; +#ifdef CONFIG_GEN_RTC + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.nvram_read_val = NULL; + ppc_md.nvram_write_val = NULL; + late_time_init = sbc82xx_time_init; +#endif /* CONFIG_GEN_RTC */ +} diff --git a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h new file mode 100644 index 000000000..b9d1c8ddb --- /dev/null +++ b/arch/ppc/platforms/sbc82xx.h @@ -0,0 +1,24 @@ +/* Board information for the SBCPowerQUICCII, which should be generic for + * all 8260 boards. The IMMR is now given to us so the hard define + * will soon be removed. All of the clock values are computed from + * the configuration SCMR and the Power-On-Reset word. + */ + +#ifndef __PPC_SBC82xx_H__ +#define __PPC_SBC82xx_H__ + +#include + +#define IMAP_ADDR 0xf0000000 +#define CPM_MAP_ADDR 0xf0000000 + +#define SBC82xx_TODC_NVRAM_ADDR 0x80000000 + +#define SBC82xx_MACADDR_NVRAM_FCC1 0x220000c9 /* JP6B */ +#define SBC82xx_MACADDR_NVRAM_SCC1 0x220000cf /* JP6A */ +#define SBC82xx_MACADDR_NVRAM_FCC2 0x220000d5 /* JP7A */ +#define SBC82xx_MACADDR_NVRAM_FCC3 0x220000db /* JP7B */ + +#define BOOTROM_RESTART_ADDR ((uint)0x40000104) + +#endif /* __PPC_SBC82xx_H__ */ diff --git a/arch/ppc/syslib/dcr.S b/arch/ppc/syslib/dcr.S new file mode 100644 index 000000000..895f10243 --- /dev/null +++ b/arch/ppc/syslib/dcr.S @@ -0,0 +1,41 @@ +/* + * arch/ppc/syslib/dcr.S + * + * "Indirect" DCR access + * + * Copyright (c) 2004 Eugene Surovegin + * + * 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 + +#define DCR_ACCESS_PROLOG(table) \ + rlwinm r3,r3,4,18,27; \ + lis r5,table@h; \ + ori r5,r5,table@l; \ + add r3,r3,r5; \ + mtctr r3; \ + bctr + +_GLOBAL(__mfdcr) + DCR_ACCESS_PROLOG(__mfdcr_table) + +_GLOBAL(__mtdcr) + DCR_ACCESS_PROLOG(__mtdcr_table) + +__mfdcr_table: + mfdcr r3,0; blr +__mtdcr_table: + mtdcr 0,r4; blr + +dcr = 1 + .rept 1023 + mfdcr r3,dcr; blr + mtdcr dcr,r4; blr + dcr = dcr + 1 + .endr diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c new file mode 100644 index 000000000..5da7bca6b --- /dev/null +++ b/arch/ppc/syslib/ibm440gx_common.c @@ -0,0 +1,212 @@ +/* + * arch/ppc/kernel/ibm440gx_common.c + * + * PPC440GX system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * 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 +#include +#include + +/* + * Calculate 440GX clocks + */ +static inline u32 __fix_zero(u32 v, u32 def){ + return v ? v : def; +} + +void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk, + unsigned int ser_clk) +{ + u32 pllc = CPR_READ(DCRN_CPR_PLLC); + u32 plld = CPR_READ(DCRN_CPR_PLLD); + u32 uart0 = SDR_READ(DCRN_SDR_UART0); + u32 uart1 = SDR_READ(DCRN_SDR_UART1); + + /* Dividers */ + u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32); + u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16); + u32 fwdvb = __fix_zero((plld >> 8) & 7, 8); + u32 lfbdv = __fix_zero(plld & 0x3f, 64); + u32 pradv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMAD) >> 24) & 7, 8); + u32 prbdv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMBD) >> 24) & 7, 8); + u32 opbdv0 = __fix_zero((CPR_READ(DCRN_CPR_OPBD) >> 24) & 3, 4); + u32 perdv0 = __fix_zero((CPR_READ(DCRN_CPR_PERD) >> 24) & 3, 4); + + /* Input clocks for primary dividers */ + u32 clk_a, clk_b; + + if (pllc & 0x40000000){ + u32 m; + + /* Feedback path */ + switch ((pllc >> 24) & 7){ + case 0: + /* PLLOUTx */ + m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv; + break; + case 1: + /* CPU */ + m = fwdva * pradv0; + break; + case 5: + /* PERClk */ + m = fwdvb * prbdv0 * opbdv0 * perdv0; + break; + default: + printk(KERN_EMERG "invalid PLL feedback source\n"); + goto bypass; + } + m *= fbdv; + p->vco = sys_clk * m; + clk_a = p->vco / fwdva; + clk_b = p->vco / fwdvb; + } + else { +bypass: + /* Bypass system PLL */ + p->vco = 0; + clk_a = clk_b = sys_clk; + } + + p->cpu = clk_a / pradv0; + p->plb = clk_b / prbdv0; + p->opb = p->plb / opbdv0; + p->ebc = p->opb / perdv0; + + /* UARTs clock */ + if (uart0 & 0x00800000) + p->uart0 = ser_clk; + else + p->uart0 = p->plb / __fix_zero(uart0 & 0xff, 256); + + if (uart1 & 0x00800000) + p->uart1 = ser_clk; + else + p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256); +} + +/* Enable L2 cache (call with IRQs disabled) */ +void __init ibm440gx_l2c_enable(void){ + u32 r; + + asm volatile ("sync" ::: "memory"); + + /* Disable SRAM */ + mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE); + mtdcr(DCRN_SRAM0_SB0CR, mfdcr(DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB1CR, mfdcr(DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB2CR, mfdcr(DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB3CR, mfdcr(DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK); + + /* Enable L2_MODE without ICU/DCU */ + r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK); + r |= L2C_CFG_L2M | L2C_CFG_SS_256; + mtdcr(DCRN_L2C0_CFG, r); + + mtdcr(DCRN_L2C0_ADDR, 0); + + /* Hardware Clear Command */ + mtdcr(DCRN_L2C0_CMD, L2C_CMD_HCC); + while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ; + + /* Clear Cache Parity and Tag Errors */ + mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE); + + /* Enable 64G snoop region starting at 0 */ + r = mfdcr(DCRN_L2C0_SNP0) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK); + r |= L2C_SNP_SSR_32G | L2C_SNP_ESR; + mtdcr(DCRN_L2C0_SNP0, r); + + r = mfdcr(DCRN_L2C0_SNP1) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK); + r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR; + mtdcr(DCRN_L2C0_SNP1, r); + + asm volatile ("sync" ::: "memory"); + + /* Enable ICU/DCU ports */ + r = mfdcr(DCRN_L2C0_CFG); + r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM + | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI | L2C_CFG_CPEI + | L2C_CFG_NAM | L2C_CFG_NBRM); + r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN + | L2C_CFG_SMCM; + mtdcr(DCRN_L2C0_CFG, r); + + asm volatile ("sync; isync" ::: "memory"); +} + +/* Disable L2 cache (call with IRQs disabled) */ +void __init ibm440gx_l2c_disable(void){ + u32 r; + + asm volatile ("sync" ::: "memory"); + + /* Disable L2C mode */ + r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_L2M | L2C_CFG_ICU | L2C_CFG_DCU); + mtdcr(DCRN_L2C0_CFG, r); + + /* Enable SRAM */ + mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) | SRAM_DPC_ENABLE); + mtdcr(DCRN_SRAM0_SB0CR, + SRAM_SBCR_BAS0 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB1CR, + SRAM_SBCR_BAS1 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB2CR, + SRAM_SBCR_BAS2 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB3CR, + SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + + asm volatile ("sync; isync" ::: "memory"); +} + +int __init ibm440gx_get_eth_grp(void) +{ + return (SDR_READ(DCRN_SDR_PFC1) & DCRN_SDR_PFC1_EPS) >> DCRN_SDR_PFC1_EPS_SHIFT; +} + +void __init ibm440gx_set_eth_grp(int group) +{ + SDR_WRITE(DCRN_SDR_PFC1, (SDR_READ(DCRN_SDR_PFC1) & ~DCRN_SDR_PFC1_EPS) | (group << DCRN_SDR_PFC1_EPS_SHIFT)); +} + +void __init ibm440gx_tah_enable(void) +{ + /* Enable TAH0 and TAH1 */ + SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) & + ~DCRN_SDR_MFR_TAH0); + SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) & + ~DCRN_SDR_MFR_TAH1); +} + +int ibm440gx_show_cpuinfo(struct seq_file *m){ + + u32 l2c_cfg = mfdcr(DCRN_L2C0_CFG); + const char* s; + if (l2c_cfg & L2C_CFG_L2M){ + switch (l2c_cfg & (L2C_CFG_ICU | L2C_CFG_DCU)){ + case L2C_CFG_ICU: s = "I-Cache only"; break; + case L2C_CFG_DCU: s = "D-Cache only"; break; + default: s = "I-Cache/D-Cache"; break; + } + } + else + s = "disabled"; + + seq_printf(m, "L2-Cache\t: %s (0x%08x 0x%08x)\n", s, + l2c_cfg, mfdcr(DCRN_L2C0_SR)); + + return 0; +} + diff --git a/arch/ppc/syslib/ibm440gx_common.h b/arch/ppc/syslib/ibm440gx_common.h new file mode 100644 index 000000000..5dbca9896 --- /dev/null +++ b/arch/ppc/syslib/ibm440gx_common.h @@ -0,0 +1,54 @@ +/* + * arch/ppc/kernel/ibm440gx_common.h + * + * PPC440GX system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * 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. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_SYSLIB_IBM440GX_COMMON_H +#define __PPC_SYSLIB_IBM440GX_COMMON_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +/* + * Please, refer to the Figure 14.1 in 440GX user manual + * + * if internal UART clock is used, ser_clk is ignored + */ +void ibm440gx_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk, + unsigned int ser_clk) __init; + +/* Enable L2 cache */ +void ibm440gx_l2c_enable(void) __init; + +/* Disable L2 cache */ +void ibm440gx_l2c_disable(void) __init; + +/* Get Ethernet Group */ +int ibm440gx_get_eth_grp(void) __init; + +/* Set Ethernet Group */ +void ibm440gx_set_eth_grp(int group) __init; + +/* Enable TAH devices */ +void ibm440gx_tah_enable(void) __init; + +/* Add L2C info to /proc/cpuinfo */ +int ibm440gx_show_cpuinfo(struct seq_file*); + +#endif /* __ASSEMBLY__ */ +#endif /* __PPC_SYSLIB_IBM440GX_COMMON_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/syslib/ibm44x_common.h b/arch/ppc/syslib/ibm44x_common.h new file mode 100644 index 000000000..ee1053ac2 --- /dev/null +++ b/arch/ppc/syslib/ibm44x_common.h @@ -0,0 +1,36 @@ +/* + * arch/ppc/kernel/ibm44x_common.h + * + * PPC44x system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * 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. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_SYSLIB_IBM44x_COMMON_H +#define __PPC_SYSLIB_IBM44x_COMMON_H + +#ifndef __ASSEMBLY__ + +/* + * All clocks are in Hz + */ +struct ibm44x_clocks { + unsigned int vco; /* VCO, 0 if system PLL is bypassed */ + unsigned int cpu; /* CPUCoreClk */ + unsigned int plb; /* PLBClk */ + unsigned int opb; /* OPBClk */ + unsigned int ebc; /* PerClk */ + unsigned int uart0; + unsigned int uart1; +}; + +#endif /* __ASSEMBLY__ */ +#endif /* __PPC_SYSLIB_IBM44x_COMMON_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c new file mode 100644 index 000000000..a5156c517 --- /dev/null +++ b/arch/ppc/syslib/ocp.c @@ -0,0 +1,485 @@ +/* + * ocp.c + * + * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org) + * Mipsys - France + * + * Derived from work (c) Armin Kuster akuster@pacbell.net + * + * Additional support and port to 2.6 LDM/sysfs by + * Matt Porter + * Copyright 2004 MontaVista Software, Inc. + * + * 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. + * + * OCP (On Chip Peripheral) is a software emulated "bus" with a + * pseudo discovery method for dumb peripherals. Usually these type + * of peripherals are found on embedded SoC (System On a Chip) + * processors or highly integrated system controllers that have + * a host bridge and many peripherals. Common examples where + * this is already used include the PPC4xx, PPC85xx, MPC52xx, + * and MV64xxx parts. + * + * This subsystem creates a standard OCP bus type within the + * device model. The devices on the OCP bus are seeded by an + * an initial OCP device array created by the arch-specific + * Device entries can be added/removed/modified through OCP + * helper functions to accomodate system and board-specific + * parameters commonly found in embedded systems. OCP also + * provides a standard method for devices to describe extended + * attributes about themselves to the system. A standard access + * method allows OCP drivers to obtain the information, both + * SoC-specific and system/board-specific, needed for operation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define DBG(x) printk x +#define DBG(x) + +extern int mem_init_done; + +extern struct ocp_def core_ocp[]; /* Static list of devices, provided by + CPU core */ + +LIST_HEAD(ocp_devices); /* List of all OCP devices */ +DECLARE_RWSEM(ocp_devices_sem); /* Global semaphores for those lists */ + +static int ocp_inited; + +/* Sysfs support */ +#define OCP_DEF_ATTR(field, format_string) \ +static ssize_t \ +show_##field(struct device *dev, char *buf) \ +{ \ + struct ocp_device *odev = to_ocp_dev(dev); \ + \ + return sprintf(buf, format_string, odev->def->field); \ +} \ +static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +OCP_DEF_ATTR(vendor, "0x%04x\n"); +OCP_DEF_ATTR(function, "0x%04x\n"); +OCP_DEF_ATTR(index, "0x%04x\n"); +#ifdef CONFIG_PTE_64BIT +OCP_DEF_ATTR(paddr, "0x%016Lx\n"); +#else +OCP_DEF_ATTR(paddr, "0x%08lx\n"); +#endif +OCP_DEF_ATTR(irq, "%d\n"); +OCP_DEF_ATTR(pm, "%lu\n"); + +void ocp_create_sysfs_dev_files(struct ocp_device *odev) +{ + struct device *dev = &odev->dev; + + /* Current OCP device def attributes */ + device_create_file(dev, &dev_attr_vendor); + device_create_file(dev, &dev_attr_function); + device_create_file(dev, &dev_attr_index); + device_create_file(dev, &dev_attr_paddr); + device_create_file(dev, &dev_attr_irq); + device_create_file(dev, &dev_attr_pm); + /* Current OCP device additions attributes */ + if (odev->def->additions && odev->def->show) + odev->def->show(dev); +} + +/** + * ocp_device_match - Match one driver to one device + * @drv: driver to match + * @dev: device to match + * + * This function returns 0 if the driver and device don't match + */ +static int +ocp_device_match(struct device *dev, struct device_driver *drv) +{ + struct ocp_device *ocp_dev = to_ocp_dev(dev); + struct ocp_driver *ocp_drv = to_ocp_drv(drv); + const struct ocp_device_id *ids = ocp_drv->id_table; + + if (!ids) + return 0; + + while (ids->vendor || ids->function) { + if ((ids->vendor == OCP_ANY_ID + || ids->vendor == ocp_dev->def->vendor) + && (ids->function == OCP_ANY_ID + || ids->function == ocp_dev->def->function)) + return 1; + ids++; + } + return 0; +} + +static int +ocp_device_probe(struct device *dev) +{ + int error = 0; + struct ocp_driver *drv; + struct ocp_device *ocp_dev; + + drv = to_ocp_drv(dev->driver); + ocp_dev = to_ocp_dev(dev); + + if (drv->probe) { + error = drv->probe(ocp_dev); + if (error >= 0) { + ocp_dev->driver = drv; + error = 0; + } + } + return error; +} + +static int +ocp_device_remove(struct device *dev) +{ + struct ocp_device *ocp_dev = to_ocp_dev(dev); + + if (ocp_dev->driver) { + if (ocp_dev->driver->remove) + ocp_dev->driver->remove(ocp_dev); + ocp_dev->driver = NULL; + } + return 0; +} + +static int +ocp_device_suspend(struct device *dev, u32 state) +{ + struct ocp_device *ocp_dev = to_ocp_dev(dev); + struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver); + + if (dev->driver && ocp_drv->suspend) + return ocp_drv->suspend(ocp_dev, state); + return 0; +} + +static int +ocp_device_resume(struct device *dev) +{ + struct ocp_device *ocp_dev = to_ocp_dev(dev); + struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver); + + if (dev->driver && ocp_drv->resume) + return ocp_drv->resume(ocp_dev); + return 0; +} + +struct bus_type ocp_bus_type = { + .name = "ocp", + .match = ocp_device_match, + .suspend = ocp_device_suspend, + .resume = ocp_device_resume, +}; + +/** + * ocp_register_driver - Register an OCP driver + * @drv: pointer to statically defined ocp_driver structure + * + * The driver's probe() callback is called either recursively + * by this function or upon later call of ocp_driver_init + * + * NOTE: Detection of devices is a 2 pass step on this implementation, + * hotswap isn't supported. First, all OCP devices are put in the device + * list, _then_ all drivers are probed on each match. + */ +int +ocp_register_driver(struct ocp_driver *drv) +{ + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &ocp_bus_type; + drv->driver.probe = ocp_device_probe; + drv->driver.remove = ocp_device_remove; + + /* register with core */ + return driver_register(&drv->driver); +} + +/** + * ocp_unregister_driver - Unregister an OCP driver + * @drv: pointer to statically defined ocp_driver structure + * + * The driver's remove() callback is called recursively + * by this function for any device already registered + */ +void +ocp_unregister_driver(struct ocp_driver *drv) +{ + DBG(("ocp: ocp_unregister_driver(%s)...\n", drv->name)); + + driver_unregister(&drv->driver); + + DBG(("ocp: ocp_unregister_driver(%s)... done.\n", drv->name)); +} + +/* Core of ocp_find_device(). Caller must hold ocp_devices_sem */ +static struct ocp_device * +__ocp_find_device(unsigned int vendor, unsigned int function, int index) +{ + struct list_head *entry; + struct ocp_device *dev, *found = NULL; + + DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index)); + + list_for_each(entry, &ocp_devices) { + dev = list_entry(entry, struct ocp_device, link); + if (vendor != OCP_ANY_ID && vendor != dev->def->vendor) + continue; + if (function != OCP_ANY_ID && function != dev->def->function) + continue; + if (index != OCP_ANY_INDEX && index != dev->def->index) + continue; + found = dev; + break; + } + + DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)... done\n", vendor, function, index)); + + return found; +} + +/** + * ocp_find_device - Find a device by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows a lookup of a given function by it's + * index, it's typically used to find the MAL or ZMII associated + * with an EMAC or similar horrors. + * You can pass vendor, though you usually want OCP_ANY_ID there... + */ +struct ocp_device * +ocp_find_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + + down_read(&ocp_devices_sem); + dev = __ocp_find_device(vendor, function, index); + up_read(&ocp_devices_sem); + + return dev; +} + +/** + * ocp_get_one_device - Find a def by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows a lookup of a given ocp_def by it's + * vendor, function, and index. The main purpose for is to + * allow modification of the def before binding to the driver + */ +struct ocp_def * +ocp_get_one_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + struct ocp_def *found = NULL; + + DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)...\n", + vendor, function, index)); + + dev = ocp_find_device(vendor, function, index); + + if (dev) + found = dev->def; + + DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)... done.\n", + vendor, function, index)); + + return found; +} + +/** + * ocp_add_one_device - Add a device + * @def: static device definition structure + * + * This function adds a device definition to the + * device list. It may only be called before + * ocp_driver_init() and will return an error + * otherwise. + */ +int +ocp_add_one_device(struct ocp_def *def) +{ + struct ocp_device *dev; + + DBG(("ocp: ocp_add_one_device()...\n")); + + /* Can't be called after ocp driver init */ + if (ocp_inited) + return 1; + + if (mem_init_done) + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + else + dev = alloc_bootmem(sizeof(*dev)); + + if (dev == NULL) + return 1; + memset(dev, 0, sizeof(*dev)); + dev->def = def; + dev->current_state = 4; + sprintf(dev->name, "OCP device %04x:%04x:%04x", + dev->def->vendor, dev->def->function, dev->def->index); + down_write(&ocp_devices_sem); + list_add_tail(&dev->link, &ocp_devices); + up_write(&ocp_devices_sem); + + DBG(("ocp: ocp_add_one_device()...done\n")); + + return 0; +} + +/** + * ocp_remove_one_device - Remove a device by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows removal of a given function by its + * index. It may only be called before ocp_driver_init() + * and will return an error otherwise. + */ +int +ocp_remove_one_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + + DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index)); + + /* Can't be called after ocp driver init */ + if (ocp_inited) + return 1; + + down_write(&ocp_devices_sem); + dev = __ocp_find_device(vendor, function, index); + list_del((struct list_head *)dev); + up_write(&ocp_devices_sem); + + DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)... done.\n", vendor, function, index)); + + return 0; +} + +/** + * ocp_for_each_device - Iterate over OCP devices + * @callback: routine to execute for each ocp device. + * @arg: user data to be passed to callback routine. + * + * This routine holds the ocp_device semaphore, so the + * callback routine cannot modify the ocp_device list. + */ +void +ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg) +{ + struct list_head *entry; + + if (callback) { + down_read(&ocp_devices_sem); + list_for_each(entry, &ocp_devices) + callback(list_entry(entry, struct ocp_device, link), + arg); + up_read(&ocp_devices_sem); + } +} + +/** + * ocp_early_init - Init OCP device management + * + * This function builds the list of devices before setup_arch. + * This allows platform code to modify the device lists before + * they are bound to drivers (changes to paddr, removing devices + * etc) + */ +int __init +ocp_early_init(void) +{ + struct ocp_def *def; + + DBG(("ocp: ocp_early_init()...\n")); + + /* Fill the devices list */ + for (def = core_ocp; def->vendor != OCP_VENDOR_INVALID; def++) + ocp_add_one_device(def); + + DBG(("ocp: ocp_early_init()... done.\n")); + + return 0; +} + +/** + * ocp_driver_init - Init OCP device management + * + * This function is meant to be called via OCP bus registration. + */ +static int __init +ocp_driver_init(void) +{ + int ret = 0, index = 0; + struct device *ocp_bus; + struct list_head *entry; + struct ocp_device *dev; + + if (ocp_inited) + return ret; + ocp_inited = 1; + + DBG(("ocp: ocp_driver_init()...\n")); + + /* Allocate/register primary OCP bus */ + ocp_bus = kmalloc(sizeof(struct device), GFP_KERNEL); + if (ocp_bus == NULL) + return 1; + memset(ocp_bus, 0, sizeof(struct device)); + strcpy(ocp_bus->bus_id, "ocp"); + + bus_register(&ocp_bus_type); + + device_register(ocp_bus); + + /* Put each OCP device into global device list */ + list_for_each(entry, &ocp_devices) { + dev = list_entry(entry, struct ocp_device, link); + sprintf(dev->dev.bus_id, "%2.2x", index); + dev->dev.parent = ocp_bus; + dev->dev.bus = &ocp_bus_type; + device_register(&dev->dev); + ocp_create_sysfs_dev_files(dev); + index++; + } + + DBG(("ocp: ocp_driver_init()... done.\n")); + + return 0; +} + +postcore_initcall(ocp_driver_init); + +EXPORT_SYMBOL(ocp_bus_type); +EXPORT_SYMBOL(ocp_find_device); +EXPORT_SYMBOL(ocp_register_driver); +EXPORT_SYMBOL(ocp_unregister_driver); diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c index dbc94842d..c059a7608 100644 --- a/arch/ppc64/kernel/pmac_feature.c +++ b/arch/ppc64/kernel/pmac_feature.c @@ -343,6 +343,10 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { PMAC_TYPE_POWERMAC_G5, g5_features, 0, }, + { "RackMac3,1", "XServe G5", + PMAC_TYPE_POWERMAC_G5, g5_features, + 0, + }, }; /* diff --git a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c new file mode 100644 index 000000000..4610cb938 --- /dev/null +++ b/arch/ppc64/lib/locks.c @@ -0,0 +1,285 @@ +/* + * Spin and read/write lock operations. + * + * Copyright (C) 2001-2004 Paul Mackerras , IBM + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2002 Dave Engebretsen , IBM + * Rework to support virtual processors + * + * 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 +#include +#include + +#ifndef CONFIG_SPINLINE + +/* + * On a system with shared processors (that is, where a physical + * processor is multiplexed between several virtual processors), + * there is no point spinning on a lock if the holder of the lock + * isn't currently scheduled on a physical processor. Instead + * we detect this situation and ask the hypervisor to give the + * rest of our timeslice to the lock holder. + * + * So that we can tell which virtual processor is holding a lock, + * we put 0x80000000 | smp_processor_id() in the lock when it is + * held. Conveniently, we have a word in the paca that holds this + * value. + */ + +/* waiting for a spinlock... */ +#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +void __spin_yield(spinlock_t *lock) +{ + unsigned int lock_value, holder_cpu, yield_count; + struct paca_struct *holder_paca; + + lock_value = lock->lock; + if (lock_value == 0) + return; + holder_cpu = lock_value & 0xffff; + BUG_ON(holder_cpu >= NR_CPUS); + holder_paca = &paca[holder_cpu]; + yield_count = holder_paca->xLpPaca.xYieldCount; + if ((yield_count & 1) == 0) + return; /* virtual cpu is currently running */ + rmb(); + if (lock->lock != lock_value) + return; /* something has changed */ +#ifdef CONFIG_PPC_ISERIES + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#else + plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); +#endif +} + +#else /* SPLPAR || ISERIES */ +#define __spin_yield(x) barrier() +#endif + +/* + * This returns the old value in the lock, so we succeeded + * in getting the lock if the return value is 0. + */ +static __inline__ unsigned long __spin_trylock(spinlock_t *lock) +{ + unsigned long tmp, tmp2; + + __asm__ __volatile__( +" lwz %1,24(13) # __spin_trylock\n\ +1: lwarx %0,0,%2\n\ + cmpwi 0,%0,0\n\ + bne- 2f\n\ + stwcx. %1,0,%2\n\ + bne- 1b\n\ + isync\n\ +2:" : "=&r" (tmp), "=&r" (tmp2) + : "r" (&lock->lock) + : "cr0", "memory"); + + return tmp; +} + +int _raw_spin_trylock(spinlock_t *lock) +{ + return __spin_trylock(lock) == 0; +} + +EXPORT_SYMBOL(_raw_spin_trylock); + +void _raw_spin_lock(spinlock_t *lock) +{ + while (1) { + if (likely(__spin_trylock(lock) == 0)) + break; + do { + HMT_low(); + __spin_yield(lock); + } while (likely(lock->lock != 0)); + HMT_medium(); + } +} + +EXPORT_SYMBOL(_raw_spin_lock); + +void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) +{ + unsigned long flags_dis; + + while (1) { + if (likely(__spin_trylock(lock) == 0)) + break; + local_save_flags(flags_dis); + local_irq_restore(flags); + do { + HMT_low(); + __spin_yield(lock); + } while (likely(lock->lock != 0)); + HMT_medium(); + local_irq_restore(flags_dis); + } +} + +EXPORT_SYMBOL(_raw_spin_lock_flags); + +void spin_unlock_wait(spinlock_t *lock) +{ + while (lock->lock) + __spin_yield(lock); +} + +EXPORT_SYMBOL(spin_unlock_wait); + +/* + * Waiting for a read lock or a write lock on a rwlock... + * This turns out to be the same for read and write locks, since + * we only know the holder if it is write-locked. + */ +#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +void __rw_yield(rwlock_t *rw) +{ + int lock_value; + unsigned int holder_cpu, yield_count; + struct paca_struct *holder_paca; + + lock_value = rw->lock; + if (lock_value >= 0) + return; /* no write lock at present */ + holder_cpu = lock_value & 0xffff; + BUG_ON(holder_cpu >= NR_CPUS); + holder_paca = &paca[holder_cpu]; + yield_count = holder_paca->xLpPaca.xYieldCount; + if ((yield_count & 1) == 0) + return; /* virtual cpu is currently running */ + rmb(); + if (rw->lock != lock_value) + return; /* something has changed */ +#ifdef CONFIG_PPC_ISERIES + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#else + plpar_hcall_norets(H_CONFER, holder_cpu, yield_count); +#endif +} + +#else /* SPLPAR || ISERIES */ +#define __rw_yield(x) barrier() +#endif + +/* + * This returns the old value in the lock + 1, + * so we got a read lock if the return value is > 0. + */ +static __inline__ long __read_trylock(rwlock_t *rw) +{ + long tmp; + + __asm__ __volatile__( +"1: lwarx %0,0,%1 # read_trylock\n\ + extsw %0,%0\n\ + addic. %0,%0,1\n\ + ble- 2f\n\ + stwcx. %0,0,%1\n\ + bne- 1b\n\ + isync\n\ +2:" : "=&r" (tmp) + : "r" (&rw->lock) + : "cr0", "xer", "memory"); + + return tmp; +} + +int _raw_read_trylock(rwlock_t *rw) +{ + return __read_trylock(rw) > 0; +} + +EXPORT_SYMBOL(_raw_read_trylock); + +void _raw_read_lock(rwlock_t *rw) +{ + while (1) { + if (likely(__read_trylock(rw) > 0)) + break; + do { + HMT_low(); + __rw_yield(rw); + } while (likely(rw->lock < 0)); + HMT_medium(); + } +} + +EXPORT_SYMBOL(_raw_read_lock); + +void _raw_read_unlock(rwlock_t *rw) +{ + long tmp; + + __asm__ __volatile__( + "eieio # read_unlock\n\ +1: lwarx %0,0,%1\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + : "=&r"(tmp) + : "r"(&rw->lock) + : "cr0", "memory"); +} + +EXPORT_SYMBOL(_raw_read_unlock); + +/* + * This returns the old value in the lock, + * so we got the write lock if the return value is 0. + */ +static __inline__ long __write_trylock(rwlock_t *rw) +{ + long tmp, tmp2; + + __asm__ __volatile__( +" lwz %1,24(13) # write_trylock\n\ +1: lwarx %0,0,%2\n\ + cmpwi 0,%0,0\n\ + bne- 2f\n\ + stwcx. %1,0,%2\n\ + bne- 1b\n\ + isync\n\ +2:" : "=&r" (tmp), "=&r" (tmp2) + : "r" (&rw->lock) + : "cr0", "memory"); + + return tmp; +} + +int _raw_write_trylock(rwlock_t *rw) +{ + return __write_trylock(rw) == 0; +} + +EXPORT_SYMBOL(_raw_write_trylock); + +void _raw_write_lock(rwlock_t *rw) +{ + while (1) { + if (likely(__write_trylock(rw) == 0)) + break; + do { + HMT_low(); + __rw_yield(rw); + } while (likely(rw->lock != 0)); + HMT_medium(); + } +} + +EXPORT_SYMBOL(_raw_write_lock); + +#endif /* CONFIG_SPINLINE */ diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 2d7efbf4f..0f8c08ad9 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -85,9 +85,10 @@ struct appldata_parameter_list { */ static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata"; static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp); + void __user *buffer, size_t *lenp); static int appldata_interval_handler(ctl_table *ctl, int write, - struct file *filp, void *buffer, + struct file *filp, + void __user *buffer, size_t *lenp); static struct ctl_table_header *appldata_sysctl_header; @@ -192,7 +193,8 @@ static void appldata_tasklet_function(unsigned long data) * wrapper function for mod_virt_timer(), because smp_call_function_on() * accepts only one parameter. */ -static void appldata_mod_vtimer_wrap(struct appldata_mod_vtimer_args *args) { +static void appldata_mod_vtimer_wrap(void *p) { + struct appldata_mod_vtimer_args *args = p; mod_virt_timer(args->timer, args->expires); } @@ -252,7 +254,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer, */ static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { int len, i; char buf[2]; @@ -309,7 +311,7 @@ out: */ static int appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { int len, i, interval; char buf[16]; @@ -347,7 +349,7 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, appldata_mod_vtimer_args.expires = per_cpu_interval; smp_call_function_on( - (void *) appldata_mod_vtimer_wrap, + appldata_mod_vtimer_wrap, &appldata_mod_vtimer_args, 0, 1, i); } @@ -370,7 +372,7 @@ out: */ static int appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { struct appldata_ops *ops = NULL, *tmp_ops; int rc, len, found; diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index a35e11af2..ce2b03578 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -32,6 +32,7 @@ int main(void) DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),); DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),); BLANK(); + DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),); DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),); DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),); DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 3886a27b8..67134eee7 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -53,7 +53,7 @@ typedef struct asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); -int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) { int err; @@ -130,7 +130,8 @@ sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t } asmlinkage int -sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigsetsize) +sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset, + size_t sigsetsize) { sigset_t saveset, newset; compat_sigset_t set32; @@ -162,11 +163,11 @@ sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigse if (do_signal(regs, &saveset)) return -EINTR; } -} +} asmlinkage long -sys32_sigaction(int sig, const struct old_sigaction32 *act, - struct old_sigaction32 *oact) +sys32_sigaction(int sig, const struct old_sigaction32 __user *act, + struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -199,9 +200,9 @@ sys32_sigaction(int sig, const struct old_sigaction32 *act, int do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact); -asmlinkage long -sys32_rt_sigaction(int sig, const struct sigaction32 *act, - struct sigaction32 *oact, size_t sigsetsize) +asmlinkage long +sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, + struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; int ret; @@ -258,7 +259,8 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, } asmlinkage long -sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) +sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, + struct pt_regs *regs) { stack_t kss, koss; int ret, err = 0; @@ -275,7 +277,9 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) } set_fs (KERNEL_DS); - ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, regs->gprs[15]); + ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL), + (stack_t __user *) (uoss ? &koss : NULL), + regs->gprs[15]); set_fs (old_fs); if (!ret && uoss) { @@ -290,7 +294,7 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) return ret; } -static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) +static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) { _s390_regs_common32 regs32; int err, i; @@ -311,7 +315,7 @@ static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) sizeof(_s390_fp_regs32)); } -static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) +static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) { _s390_regs_common32 regs32; int err, i; @@ -343,7 +347,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) asmlinkage long sys32_sigreturn(struct pt_regs *regs) { - sigframe32 *frame = (sigframe32 *)regs->gprs[15]; + sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; sigset_t set; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -365,11 +369,11 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) badframe: force_sig(SIGSEGV, current); return 0; -} +} asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) { - rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15]; + rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; sigset_t set; stack_t st; __u32 ss_sp; @@ -399,8 +403,8 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - set_fs (KERNEL_DS); - do_sigaltstack(&st, NULL, regs->gprs[15]); + set_fs (KERNEL_DS); + do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]); set_fs (old_fs); return regs->gprs[2]; @@ -418,7 +422,7 @@ badframe: /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long sp; @@ -439,7 +443,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) sp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((sp - frame_size) & -8ul); + return (void __user *)((sp - frame_size) & -8ul); } static inline int map_signal(int sig) @@ -455,7 +459,7 @@ static inline int map_signal(int sig) static void setup_frame32(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - sigframe32 *frame = get_sigframe(ka, regs, sizeof(sigframe32)); + sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32)); if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32))) goto give_sigsegv; @@ -474,12 +478,12 @@ static void setup_frame32(int sig, struct k_sigaction *ka, } else { regs->gprs[14] = (__u64) frame->retcode; if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, - (u16 *)(frame->retcode))) + (u16 __user *)(frame->retcode))) goto give_sigsegv; } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (unsigned int *) frame)) + if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ @@ -505,7 +509,7 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { int err = 0; - rt_sigframe32 *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); + rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32))) goto give_sigsegv; @@ -531,11 +535,11 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, } else { regs->gprs[14] = (__u64) frame->retcode; err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, - (u16 *)(frame->retcode)); + (u16 __user *)(frame->retcode)); } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (unsigned int *) frame)) + if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index d2980b671..540a9a8bc 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -62,9 +62,9 @@ extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); /* internal function prototyes */ static int debug_init(void); -static ssize_t debug_output(struct file *file, char *user_buf, +static ssize_t debug_output(struct file *file, char __user *user_buf, size_t user_len, loff_t * offset); -static ssize_t debug_input(struct file *file, const char *user_buf, +static ssize_t debug_input(struct file *file, const char __user *user_buf, size_t user_len, loff_t * offset); static int debug_open(struct inode *inode, struct file *file); static int debug_close(struct inode *inode, struct file *file); @@ -74,10 +74,10 @@ static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf); static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char *user_buf, + struct file *file, const char __user *user_buf, size_t user_buf_size, loff_t * offset); static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char *user_buf, + struct file *file, const char __user *user_buf, size_t user_buf_size, loff_t * offset); static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, char *out_buf, const char *in_buf); @@ -416,10 +416,10 @@ out: * - copies formated debug entries to the user buffer */ -static ssize_t debug_output(struct file *file, /* file descriptor */ - char *user_buf, /* user buffer */ - size_t len, /* length of buffer */ - loff_t *offset /* offset in the file */ ) +static ssize_t debug_output(struct file *file, /* file descriptor */ + char __user *user_buf, /* user buffer */ + size_t len, /* length of buffer */ + loff_t *offset) /* offset in the file */ { size_t count = 0; size_t entry_offset, size = 0; @@ -462,7 +462,7 @@ out: */ static ssize_t debug_input(struct file *file, - const char *user_buf, size_t length, + const char __user *user_buf, size_t length, loff_t *offset) { int rc = 0; @@ -942,7 +942,7 @@ static int debug_prolog_level_fn(debug_info_t * id, */ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char *user_buf, + struct file *file, const char __user *user_buf, size_t in_buf_size, loff_t * offset) { char input_buf[1]; @@ -1004,9 +1004,9 @@ void debug_flush(debug_info_t* id, int area) /* * view function: flushes debug areas */ - + static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char *user_buf, + struct file *file, const char __user *user_buf, size_t in_buf_size, loff_t * offset) { char input_buf[1]; diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 229f4aff8..068653a5e 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -478,9 +478,80 @@ startup:basr %r13,0 # get base mvcle %r2,%r4,0 # clear mem jo .-4 # branch back, if not finish + l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word +.Lservicecall: + stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts + + stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 + la %r1,0x200 # set bit 22 + o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 + st %r1,.Lcr-.LPG1(%r13) + lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 + + mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw + la %r1, .Lsclph-.LPG1(%r13) + a %r1,__LC_EXT_NEW_PSW+4 # set handler + st %r1,__LC_EXT_NEW_PSW+4 + + la %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff + la %r1, .Lsccb-PARMAREA(%r4) # our sccb + .insn rre,0xb2200000,%r2,%r1 # service call + ipm %r1 + srl %r1,28 # get cc code + xr %r3, %r3 + chi %r1,3 + be .Lfchunk-.LPG1(%r13) # leave + chi %r1,2 + be .Lservicecall-.LPG1(%r13) + lpsw .Lwaitsclp-.LPG1(%r13) +.Lsclph: + lh %r1,.Lsccbr-PARMAREA(%r4) + chi %r1,0x10 # 0x0010 is the sucess code + je .Lprocsccb # let's process the sccb + chi %r1,0x1f0 + bne .Lfchunk-.LPG1(%r13) # unhandled error code + c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced + bne .Lfchunk-.LPG1(%r13) # if no, give up + l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP + b .Lservicecall-.LPG1(%r13) +.Lprocsccb: + lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 + chi %r1,0x00 + jne .Lscnd + l %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one +.Lscnd: + xr %r3,%r3 # same logic + ic %r3,.Lscpa1-PARMAREA(%r4) + chi %r3,0x00 + jne .Lcompmem + l %r3,.Lscpa2-PARMAREA(%r13) +.Lcompmem: + mr %r2,%r1 # mem in MB on 128-bit + l %r1,.Lonemb-.LPG1(%r13) + mr %r2,%r1 # mem size in bytes in %r3 + b .Lfchunk-.LPG1(%r13) + +.Lpmask: + .byte 0 +.align 8 +.Lpcext:.long 0x00080000,0x80000000 +.Lcr: + .long 0x00 # place holder for cr0 +.Lwaitsclp: + .long 0x020A0000 + .long .Lsclph +.Lrcp: + .int 0x00120001 # Read SCP forced code +.Lrcp2: + .int 0x00020001 # Read SCP code +.Lonemb: + .int 0x100000 +.Lfchunk: + # # find memory chunks. # + lr %r9,%r3 # end of mem mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) la %r1,1 # test in increments of 128KB sll %r1,17 @@ -488,38 +559,46 @@ startup:basr %r13,0 # get base slr %r4,%r4 # set start of chunk to zero slr %r5,%r5 # set end of chunk to zero slr %r6,%r6 # set access code to zero + la %r10, MEMORY_CHUNKS # number of chunks .Lloop: tprot 0(%r5),0 # test protection of first byte ipm %r7 srl %r7,28 clr %r6,%r7 # compare cc with last access code be .Lsame-.LPG1(%r13) - clr %r4,%r5 # chunk size > 0? - be .Lsize0-.LPG1(%r13) - st %r4,0(%r3) # store start address of chunk - lr %r0,%r5 - slr %r0,%r4 - st %r0,4(%r3) # store size of chunk - st %r6,8(%r3) # store type of chunk - la %r3,12(%r3) - lr %r4,%r5 # set start to end -.Lsize0: - lr %r6,%r7 # set access code to last cc + b .Lchkmem-.LPG1(%r13) .Lsame: ar %r5,%r1 # add 128KB to end of chunk bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: # > 2GB or tprot got a program check clr %r4,%r5 # chunk size > 0? - be .Ldonemem-.LPG1(%r13) + be .Lchkloop-.LPG1(%r13) st %r4,0(%r3) # store start address of chunk lr %r0,%r5 slr %r0,%r4 st %r0,4(%r3) # store size of chunk st %r6,8(%r3) # store type of chunk + la %r3,12(%r3) + l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size + st %r5,0(%r4) # store last end to memory size + ahi %r10,-1 # update chunk number +.Lchkloop: + lr %r6,%r7 # set access code to last cc + # we got an exception or we're starting a new + # chunk , we must check if we should + # still try to find valid memory (if we detected + # the amount of available storage), and if we + # have chunks left + xr %r0,%r0 + clr %r0,%r9 # did we detect memory? + je .Ldonemem # if not, leave + chi %r10,0 # do we have chunks left? + je .Ldonemem + alr %r5,%r1 # add 128KB to end of chunk + lr %r4,%r5 # potential new chunk + clr %r5,%r9 # should we go on? + jl .Lloop .Ldonemem: - l %r1,.Lmemsize-.LPG1(%r13) # address of variable memory_size - st %r5,0(%r1) # store last end to memory size - l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # # find out if we are running under VM @@ -631,6 +710,23 @@ _pstart: .byte "root=/dev/ram0 ro" .byte 0 .org 0x11000 +.Lsccb: + .hword 0x1000 # length, one page + .byte 0x00,0x00,0x00 + .byte 0x80 # variable response bit set +.Lsccbr: + .hword 0x00 # response code +.Lscpincr1: + .hword 0x00 +.Lscpa1: + .byte 0x00 + .fill 89,1,0 +.Lscpa2: + .int 0x00 +.Lscpincr2: + .quad 0x00 + .fill 3984,1,0 + .org 0x12000 .global _pend _pend: diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index c380e2b9c..26caebd7d 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -480,12 +480,81 @@ startup:basr %r13,0 # get base mvcle %r2,%r4,0 # clear mem jo .-4 # branch back, if not finish + l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word +.Lservicecall: + stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts + + stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 + la %r1,0x200 # set bit 22 + og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 + stg %r1,.Lcr-.LPG1(%r13) + lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 + + mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw + larl %r1,.Lsclph + stg %r1,__LC_EXT_NEW_PSW+8 # set handler + + larl %r4,_pstart # %r4 is our index for sccb stuff + la %r1,.Lsccb-PARMAREA(%r4) # our sccb + .insn rre,0xb2200000,%r2,%r1 # service call + ipm %r1 + srl %r1,28 # get cc code + xr %r3,%r3 + chi %r1,3 + be .Lfchunk-.LPG1(%r13) # leave + chi %r1,2 + be .Lservicecall-.LPG1(%r13) + lpsw .Lwaitsclp-.LPG1(%r13) +.Lsclph: + lh %r1,.Lsccbr-PARMAREA(%r4) + chi %r1,0x10 # 0x0010 is the sucess code + je .Lprocsccb # let's process the sccb + chi %r1,0x1f0 + bne .Lfchunk-.LPG1(%r13) # unhandled error code + c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced + bne .Lfchunk-.LPG1(%r13) # if no, give up + l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP + b .Lservicecall-.LPG1(%r13) +.Lprocsccb: + lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 + chi %r1,0x00 + jne .Lscnd + lg %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one +.Lscnd: + xr %r3,%r3 # same logic + ic %r3,.Lscpa1-PARMAREA(%r4) + chi %r3,0x00 + jne .Lcompmem + l %r3,.Lscpa2-PARMAREA(%r13) +.Lcompmem: + mlgr %r2,%r1 # mem in MB on 128-bit + l %r1,.Lonemb-.LPG1(%r13) + mlgr %r2,%r1 # mem size in bytes in %r3 + b .Lfchunk-.LPG1(%r13) + +.Lpmask: + .byte 0 + .align 8 +.Lcr: + .quad 0x00 # place holder for cr0 +.Lwaitsclp: + .long 0x020A0000 + .quad .Lsclph +.Lrcp: + .int 0x00120001 # Read SCP forced code +.Lrcp2: + .int 0x00020001 # Read SCP code +.Lonemb: + .int 0x100000 + +.Lfchunk: # set program check new psw mask mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # # find memory chunks. # + lgr %r9,%r3 # end of mem larl %r1,.Lchkmem # set program check address stg %r1,__LC_PGM_NEW_PSW+8 la %r1,1 # test in increments of 128KB @@ -494,51 +563,51 @@ startup:basr %r13,0 # get base slgr %r4,%r4 # set start of chunk to zero slgr %r5,%r5 # set end of chunk to zero slr %r6,%r6 # set access code to zero + la %r10,MEMORY_CHUNKS # number of chunks .Lloop: tprot 0(%r5),0 # test protection of first byte ipm %r7 srl %r7,28 clr %r6,%r7 # compare cc with last access code je .Lsame - clgr %r4,%r5 # chunk size > 0? - je .Lsize0 - stg %r4,0(%r3) # store start address of chunk - lgr %r0,%r5 - slgr %r0,%r4 - stg %r0,8(%r3) # store size of chunk - st %r6,20(%r3) # store type of chunk - la %r3,24(%r3) - lgr %r4,%r5 # set start to end - larl %r8,memory_size - stg %r5,0(%r8) # store memory size -.Lsize0: - lr %r6,%r7 # set access code to last cc + j .Lchkmem .Lsame: algr %r5,%r1 # add 128KB to end of chunk - brc 12,.Lloop + # no need to check here, + brc 12,.Lloop # this is the same chunk .Lchkmem: # > 16EB or tprot got a program check clgr %r4,%r5 # chunk size > 0? - je .Ldonemem + je .Lchkloop stg %r4,0(%r3) # store start address of chunk lgr %r0,%r5 slgr %r0,%r4 stg %r0,8(%r3) # store size of chunk st %r6,20(%r3) # store type of chunk la %r3,24(%r3) - lgr %r4,%r5 larl %r8,memory_size stg %r5,0(%r8) # store memory size -# -# Running native the HSA is located at 2GB and we will get an -# addressing exception trying to access it. We have to restart -# the scan at 2GB to find out if the machine has more than 2GB. -# + ahi %r10,-1 # update chunk number +.Lchkloop: + lr %r6,%r7 # set access code to last cc + # we got an exception or we're starting a new + # chunk , we must check if we should + # still try to find valid memory (if we detected + # the amount of available storage), and if we + # have chunks left lghi %r4,1 sllg %r4,%r4,31 clgr %r5,%r4 - jhe .Ldonemem - lgr %r5,%r4 - j .Lloop + je .Lhsaskip + xr %r0, %r0 + clgr %r0, %r9 # did we detect memory? + je .Ldonemem # if not, leave + chi %r10, 0 # do we have chunks left? + je .Ldonemem +.Lhsaskip: + algr %r5,%r1 # add 128KB to end of chunk + lgr %r4,%r5 # potential new chunk + clgr %r5,%r9 # should we go on? + jl .Lloop .Ldonemem: larl %r12,machine_flags @@ -640,6 +709,23 @@ _pstart: .byte "root=/dev/ram0 ro" .byte 0 .org 0x11000 +.Lsccb: + .hword 0x1000 # length, one page + .byte 0x00,0x00,0x00 + .byte 0x80 # variable response bit set +.Lsccbr: + .hword 0x00 # response code +.Lscpincr1: + .hword 0x00 +.Lscpa1: + .byte 0x00 + .fill 89,1,0 +.Lscpa2: + .int 0x00 +.Lscpincr2: + .quad 0x00 + .fill 3984,1,0 + .org 0x12000 .global _pend _pend: diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c index a6fad9c93..f219748d7 100644 --- a/arch/s390/kernel/profile.c +++ b/arch/s390/kernel/profile.c @@ -19,7 +19,8 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, return len; } -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, +static int prof_cpu_mask_write_proc (struct file *file, + const char __user *buffer, unsigned long count, void *data) { cpumask_t *mask = (cpumask_t *)data; diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 832e7582a..5ba86ba1a 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -44,25 +44,6 @@ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); -/* - * string functions - */ -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(strlen); -EXPORT_SYMBOL_NOVERS(strchr); -EXPORT_SYMBOL_NOVERS(strcmp); -EXPORT_SYMBOL_NOVERS(strncat); -EXPORT_SYMBOL_NOVERS(strncmp); -EXPORT_SYMBOL_NOVERS(strncpy); -EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strcpy); - /* * binfmt_elf loader */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 7ca8a8706..d549ad5c2 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -53,7 +53,9 @@ unsigned int console_device = -1; unsigned int console_irq = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; -struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } }; +struct { + unsigned long addr, size, type; +} memory_chunk[MEMORY_CHUNKS] = { { 0 } }; #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 int cpus_initialized = 0; diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 2379b6734..d32b2c44b 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -77,8 +77,9 @@ sys_sigsuspend(struct pt_regs * regs, int history0, int history1, } } -asmlinkage int -sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) +asmlinkage long +sys_rt_sigsuspend(struct pt_regs *regs, sigset_t __user *unewset, + size_t sigsetsize) { sigset_t saveset, newset; @@ -105,9 +106,9 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) } } -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) +asmlinkage long +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -137,8 +138,9 @@ sys_sigaction(int sig, const struct old_sigaction *act, return ret; } -asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) +asmlinkage long +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs) { return do_sigaltstack(uss, uoss, regs->gprs[15]); } @@ -146,7 +148,7 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) /* Returns non-zero on fault. */ -static int save_sigregs(struct pt_regs *regs, _sigregs *sregs) +static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { unsigned long old_mask = regs->psw.mask; int err; @@ -175,7 +177,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs *sregs) } /* Returns positive number on error */ -static int restore_sigregs(struct pt_regs *regs, _sigregs *sregs) +static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { unsigned long old_mask = regs->psw.mask; int err; @@ -208,7 +210,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs *sregs) asmlinkage long sys_sigreturn(struct pt_regs *regs) { - sigframe *frame = (sigframe *)regs->gprs[15]; + sigframe __user *frame = (sigframe __user *)regs->gprs[15]; sigset_t set; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -234,7 +236,7 @@ badframe: asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) { - rt_sigframe *frame = (rt_sigframe *)regs->gprs[15]; + rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15]; sigset_t set; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -269,7 +271,7 @@ badframe: /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long sp; @@ -290,7 +292,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) sp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((sp - frame_size) & -8ul); + return (void __user *)((sp - frame_size) & -8ul); } static inline int map_signal(int sig) @@ -306,7 +308,9 @@ static inline int map_signal(int sig) static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - sigframe *frame = get_sigframe(ka, regs, sizeof(sigframe)); + sigframe __user *frame; + + frame = get_sigframe(ka, regs, sizeof(sigframe)); if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe))) goto give_sigsegv; @@ -326,13 +330,13 @@ static void setup_frame(int sig, struct k_sigaction *ka, } else { regs->gprs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE; - if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, - (u16 *)(frame->retcode))) + if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, + (u16 __user *)(frame->retcode))) goto give_sigsegv; } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (addr_t *) frame)) + if (__put_user(regs->gprs[15], (addr_t __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ @@ -358,7 +362,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { int err = 0; - rt_sigframe *frame = get_sigframe(ka, regs, sizeof(rt_sigframe)); + rt_sigframe __user *frame; + + frame = get_sigframe(ka, regs, sizeof(rt_sigframe)); if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe))) goto give_sigsegv; @@ -385,12 +391,12 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } else { regs->gprs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE; - err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, - (u16 *)(frame->retcode)); + err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, + (u16 __user *)(frame->retcode)); } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (addr_t *) frame)) + if (__put_user(regs->gprs[15], (addr_t __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index b2e83876f..537700fbe 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -188,7 +188,7 @@ void show_registers(struct pt_regs *regs) printk("%s Code: ", mode); for (i = 0; i < 20; i++) { unsigned char c; - if (__get_user(c, (char *)(regs->psw.addr + i))) { + if (__get_user(c, (char __user *)(regs->psw.addr + i))) { printk(" Bad PSW."); break; } @@ -391,7 +391,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) local_irq_enable(); if (regs->psw.mask & PSW_MASK_PSTATE) - get_user(*((__u16 *) opcode), location); + get_user(*((__u16 *) opcode), (__u16 __user *)location); else *((__u16 *)opcode)=*((__u16 *)location); if (*((__u16 *)opcode)==S390_BREAKPOINT_U16) diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index 3cf8418ae..a8758b1d2 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,6 +4,6 @@ EXTRA_AFLAGS := -traditional -lib-y += delay.o -lib-$(CONFIG_ARCH_S390_31) += memset.o strcmp.o strcpy.o strncpy.o uaccess.o -lib-$(CONFIG_ARCH_S390X) += memset64.o strcmp64.o strcpy64.o strncpy64.o uaccess64.o +lib-y += delay.o string.o +lib-$(CONFIG_ARCH_S390_31) += uaccess.o +lib-$(CONFIG_ARCH_S390X) += uaccess64.o diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c new file mode 100644 index 000000000..dea4957d0 --- /dev/null +++ b/arch/s390/lib/string.c @@ -0,0 +1,405 @@ +/* + * arch/s390/lib/string.c + * Optimized string functions + * + * S390 version + * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + +#define IN_ARCH_STRING_C 1 + +#include +#include + +/* + * Helper functions to find the end of a string + */ +static inline char *__strend(const char *s) +{ + register unsigned long r0 asm("0") = 0; + + asm volatile ("0: srst %0,%1\n" + " jo 0b" + : "+d" (r0), "+a" (s) : : "cc" ); + return (char *) r0; +} + +static inline char *__strnend(const char *s, size_t n) +{ + register unsigned long r0 asm("0") = 0; + const char *p = s + n; + + asm volatile ("0: srst %0,%1\n" + " jo 0b" + : "+d" (p), "+a" (s) : "d" (r0) : "cc" ); + return (char *) p; +} + +/** + * strlen - Find the length of a string + * @s: The string to be sized + * + * returns the length of @s + */ +size_t strlen(const char *s) +{ + return __strend(s) - s; +} +EXPORT_SYMBOL_NOVERS(strlen); + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @n: The maximum number of bytes to search + * + * returns the minimum of the length of @s and @n + */ +size_t strnlen(const char * s, size_t n) +{ + return __strnend(s, n) - s; +} +EXPORT_SYMBOL_NOVERS(strnlen); + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * + * returns a pointer to @dest + */ +char *strcpy(char *dest, const char *src) +{ + register int r0 asm("0") = 0; + char *ret = dest; + + asm volatile ("0: mvst %0,%1\n" + " jo 0b" + : "+&a" (dest), "+&a" (src) : "d" (r0) + : "cc", "memory" ); + return ret; +} +EXPORT_SYMBOL_NOVERS(strcpy); + +/** + * strlcpy - Copy a %NUL terminated string into a sized buffer + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @size: size of destination buffer + * + * Compatible with *BSD: the result is always a valid + * NUL-terminated string that fits in the buffer (unless, + * of course, the buffer size is zero). It does not pad + * out the result like strncpy() does. + */ +size_t strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = __strend(src) - src; + + if (size) { + size_t len = (ret >= size) ? size-1 : ret; + dest[len] = '\0'; + __builtin_memcpy(dest, src, len); + } + return ret; +} +EXPORT_SYMBOL_NOVERS(strlcpy); + +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @n: The maximum number of bytes to copy + * + * The result is not %NUL-terminated if the source exceeds + * @n bytes. + */ +char *strncpy(char *dest, const char *src, size_t n) +{ + size_t len = __strnend(src, n) - src; + __builtin_memset(dest + len, 0, n - len); + __builtin_memcpy(dest, src, len); + return dest; +} +EXPORT_SYMBOL_NOVERS(strncpy); + +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * + * returns a pointer to @dest + */ +char *strcat(char *dest, const char *src) +{ + register int r0 asm("0") = 0; + unsigned long dummy; + char *ret = dest; + + asm volatile ("0: srst %0,%1\n" + " jo 0b\n" + "1: mvst %0,%2\n" + " jo 1b" + : "=&a" (dummy), "+a" (dest), "+a" (src) + : "d" (r0), "0" (0UL) : "cc", "memory" ); + return ret; +} +EXPORT_SYMBOL_NOVERS(strcat); + +/** + * strlcat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @n: The size of the destination buffer. + */ +size_t strlcat(char *dest, const char *src, size_t n) +{ + size_t dsize = __strend(dest) - dest; + size_t len = __strend(src) - src; + size_t res = dsize + len; + + if (dsize < n) { + dest += dsize; + n -= dsize; + if (len >= n) + len = n - 1; + dest[len] = '\0'; + __builtin_memcpy(dest, src, len); + } + return res; +} +EXPORT_SYMBOL_NOVERS(strlcat); + +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @n: The maximum numbers of bytes to copy + * + * returns a pointer to @dest + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ +char *strncat(char *dest, const char *src, size_t n) +{ + size_t len = __strnend(src, n) - src; + char *p = __strend(dest); + + p[len] = '\0'; + __builtin_memcpy(p, src, len); + return dest; +} +EXPORT_SYMBOL_NOVERS(strncat); + +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + * + * returns 0 if @cs and @ct are equal, + * < 0 if @cs is less than @ct + * > 0 if @cs is greater than @ct + */ +int strcmp(const char *cs, const char *ct) +{ + register int r0 asm("0") = 0; + int ret = 0; + + asm volatile ("0: clst %2,%3\n" + " jo 0b\n" + " je 1f\n" + " ic %0,0(%2)\n" + " ic %1,0(%3)\n" + " sr %0,%1\n" + "1:" + : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct) + : : "cc" ); + return ret; +} +EXPORT_SYMBOL_NOVERS(strcmp); + +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strrchr(const char * s, int c) +{ + size_t len = __strend(s) - s; + + if (len) + do { + if (s[len] == (char) c) + return (char *) s + len; + } while (--len > 0); + return 0; +} +EXPORT_SYMBOL_NOVERS(strrchr); + +/** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ +char * strstr(const char * s1,const char * s2) +{ + int l1, l2; + + l2 = __strend(s2) - s2; + if (!l2) + return (char *) s1; + l1 = __strend(s1) - s1; + while (l1-- >= l2) { + register unsigned long r2 asm("2") = (unsigned long) s1; + register unsigned long r3 asm("3") = (unsigned long) l2; + register unsigned long r4 asm("4") = (unsigned long) s2; + register unsigned long r5 asm("5") = (unsigned long) l2; + int cc; + + asm volatile ("0: clcle %1,%3,0\n" + " jo 0b\n" + " ipm %0\n" + " srl %0,28" + : "=&d" (cc), "+a" (r2), "+a" (r3), + "+a" (r4), "+a" (r5) : : "cc" ); + if (!cc) + return (char *) s1; + s1++; + } + return 0; +} +EXPORT_SYMBOL_NOVERS(strstr); + +/** + * memchr - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or %NULL + * if @c is not found + */ +void *memchr(const void *s, int c, size_t n) +{ + register int r0 asm("0") = (char) c; + const void *ret = s + n; + + asm volatile ("0: srst %0,%1\n" + " jo 0b\n" + " jl 1f\n" + " la %0,0\n" + "1:" + : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); + return (void *) ret; +} +EXPORT_SYMBOL_NOVERS(memchr); + +/** + * memcmp - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ +int memcmp(const void *cs, const void *ct, size_t n) +{ + register unsigned long r2 asm("2") = (unsigned long) cs; + register unsigned long r3 asm("3") = (unsigned long) n; + register unsigned long r4 asm("4") = (unsigned long) ct; + register unsigned long r5 asm("5") = (unsigned long) n; + int ret; + + asm volatile ("0: clcle %1,%3,0\n" + " jo 0b\n" + " ipm %0\n" + " srl %0,28" + : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5) + : : "cc" ); + if (ret) + ret = *(char *) r2 - *(char *) r4; + return ret; +} +EXPORT_SYMBOL_NOVERS(memcmp); + +/** + * memscan - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or 1 byte past + * the area if @c is not found + */ +void *memscan(void *s, int c, size_t n) +{ + register int r0 asm("0") = (char) c; + const void *ret = s + n; + + asm volatile ("0: srst %0,%1\n" + " jo 0b\n" + : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); + return (void *) ret; +} +EXPORT_SYMBOL_NOVERS(memscan); + +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @n: The size of the area. + * + * returns a pointer to @dest + */ +void *memcpy(void *dest, const void *src, size_t n) +{ + return __builtin_memcpy(dest, src, n); +} +EXPORT_SYMBOL_NOVERS(memcpy); + +/** + * bcopy - Copy one area of memory to another + * @src: Where to copy from + * @dest: Where to copy to + * @n: The size of the area. + * + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. + */ +void bcopy(const void *srcp, void *destp, size_t n) +{ + __builtin_memcpy(destp, srcp, n); +} +EXPORT_SYMBOL_NOVERS(bcopy); + +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @n: The size of the area. + * + * returns a pointer to @s + */ +void *memset(void *s, int c, size_t n) +{ + char *xs; + + if (c == 0) + return __builtin_memset(s, 0, n); + + xs = (char *) s; + if (n > 0) + do { + *xs++ = c; + } while (--n > 0); + return s; +} +EXPORT_SYMBOL_NOVERS(memset); + +/* + * missing exports for string functions defined in lib/string.c + */ +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL_NOVERS(strnchr); +EXPORT_SYMBOL_NOVERS(strncmp); +EXPORT_SYMBOL_NOVERS(strpbrk); diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S index ef26df4c9..e8029ef42 100644 --- a/arch/s390/lib/uaccess.S +++ b/arch/s390/lib/uaccess.S @@ -154,46 +154,57 @@ __clear_user_asm: .align 4 .text .globl __strncpy_from_user_asm - # %r2 = dst, %r3 = src, %r4 = count + # %r2 = count, %r3 = dst, %r4 = src __strncpy_from_user_asm: lhi %r0,0 - lhi %r1,1 - lhi %r5,0 -0: mvcp 0(%r1,%r2),0(%r3),%r0 - tm 0(%r2),0xff - jz 1f - la %r2,1(%r2) - la %r3,1(%r3) - ahi %r5,1 - clr %r5,%r4 - jl 0b -1: lr %r2,%r5 + lr %r1,%r4 + la %r4,0(%r4) # clear high order bit from %r4 + la %r2,0(%r2,%r4) # %r2 points to first byte after string + sacf 256 +0: srst %r2,%r1 + jo 0b + sacf 0 + lr %r1,%r2 + jh 1f # \0 found in string ? + ahi %r1,1 # include \0 in copy +1: slr %r1,%r4 # %r1 = copy length (without \0) + slr %r2,%r4 # %r2 = return length (including \0) +2: mvcp 0(%r1,%r3),0(%r4),%r0 + jnz 3f br %r14 -2: lhi %r2,-EFAULT +3: la %r3,256(%r3) + la %r4,256(%r4) + ahi %r1,-256 + mvcp 0(%r1,%r3),0(%r4),%r0 + jnz 3b br %r14 - .section __ex_table,"a" - .long 0b,2b +4: sacf 0 + lhi %r2,-EFAULT + br %r14 + .section __ex_table,"a" + .long 0b,4b .previous .align 4 .text .globl __strnlen_user_asm - # %r2 = src, %r3 = count + # %r2 = count, %r3 = src __strnlen_user_asm: lhi %r0,0 - lhi %r1,1 - lhi %r5,0 -0: mvcp 24(%r1,%r15),0(%r2),%r0 - ahi %r5,1 - tm 24(%r15),0xff - jz 1f - la %r2,1(%r2) - clr %r5,%r3 - jl 0b -1: lr %r2,%r5 + lr %r1,%r3 + la %r3,0(%r3) # clear high order bit from %r4 + la %r2,0(%r2,%r3) # %r2 points to first byte after string + sacf 256 +0: srst %r2,%r1 + jo 0b + sacf 0 + jh 1f # \0 found in string ? + ahi %r2,1 # strnlen_user result includes the \0 +1: slr %r2,%r3 br %r14 -2: lhi %r2,-EFAULT +2: sacf 0 + lhi %r2,-EFAULT br %r14 - .section __ex_table,"a" + .section __ex_table,"a" .long 0b,2b .previous diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S index c12f70a67..0ca56972f 100644 --- a/arch/s390/lib/uaccess64.S +++ b/arch/s390/lib/uaccess64.S @@ -152,46 +152,55 @@ __clear_user_asm: .align 4 .text .globl __strncpy_from_user_asm - # %r2 = dst, %r3 = src, %r4 = count + # %r2 = count, %r3 = dst, %r4 = src __strncpy_from_user_asm: lghi %r0,0 - lghi %r1,1 - lghi %r5,0 -0: mvcp 0(%r1,%r2),0(%r3),%r0 - tm 0(%r2),0xff - jz 1f - la %r2,1(%r2) - la %r3,1(%r3) - aghi %r5,1 - clgr %r5,%r4 - jl 0b -1: lgr %r2,%r5 + lgr %r1,%r4 + la %r2,0(%r2,%r4) # %r2 points to first byte after string + sacf 256 +0: srst %r2,%r1 + jo 0b + sacf 0 + lgr %r1,%r2 + jh 1f # \0 found in string ? + aghi %r1,1 # include \0 in copy +1: slgr %r1,%r4 # %r1 = copy length (without \0) + slgr %r2,%r4 # %r2 = return length (including \0) +2: mvcp 0(%r1,%r3),0(%r4),%r0 + jnz 3f br %r14 -2: lghi %r2,-EFAULT +3: la %r3,256(%r3) + la %r4,256(%r4) + aghi %r1,-256 + mvcp 0(%r1,%r3),0(%r4),%r0 + jnz 3b br %r14 - .section __ex_table,"a" - .quad 0b,2b +4: sacf 0 + lghi %r2,-EFAULT + br %r14 + .section __ex_table,"a" + .quad 0b,4b .previous .align 4 .text .globl __strnlen_user_asm - # %r2 = src, %r3 = count + # %r2 = count, %r3 = src __strnlen_user_asm: lghi %r0,0 - lghi %r1,1 - lghi %r5,0 -0: mvcp 24(%r1,%r15),0(%r2),%r0 - aghi %r5,1 - tm 24(%r15),0xff - jz 1f - la %r2,1(%r2) - clgr %r5,%r3 - jl 0b -1: lgr %r2,%r5 + lgr %r1,%r3 + la %r2,0(%r2,%r3) # %r2 points to first byte after string + sacf 256 +0: srst %r2,%r1 + jo 0b + sacf 0 + jh 1f # \0 found in string ? + aghi %r2,1 # strnlen_user result includes the \0 +1: slgr %r2,%r3 br %r14 -2: lghi %r2,-EFAULT +2: sacf 0 + lghi %r2,-EFAULT br %r14 - .section __ex_table,"a" + .section __ex_table,"a" .quad 0b,2b .previous diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index ea3db122d..b0b2714ea 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -55,7 +55,9 @@ struct dcss_segment { static spinlock_t dcss_lock = SPIN_LOCK_UNLOCKED; static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); -extern struct {unsigned long addr, size, type;} memory_chunk[16]; +extern struct { + unsigned long addr, size, type; +} memory_chunk[MEMORY_CHUNKS]; /* * Create the 8 bytes, ebcdic VM segment name from @@ -258,16 +260,16 @@ int segment_load(char *name, int segtype, unsigned long *addr, shared segment */ dcss_diag_query(dcss_name, &rwattr, &shattr, &segstart, &segend); /* does segment collide with main memory? */ - for (i=0; i<16; i++) { - if (memory_chunk[i].type != 0) - continue; - if (memory_chunk[i].addr > segend) - continue; - if (memory_chunk[i].addr + memory_chunk[i].size <= segstart) - continue; - spin_unlock(&dcss_lock); - return -ENOENT; - } + for (i=0; i < MEMORY_CHUNKS; i++) { + if (memory_chunk[i].type != 0) + continue; + if (memory_chunk[i].addr > segend) + continue; + if (memory_chunk[i].addr + memory_chunk[i].size <= segstart) + continue; + spin_unlock(&dcss_lock); + return -ENOENT; + } /* or does it collide with other (loaded) segments? */ list_for_each(l, &dcss_list) { tmp = list_entry(l, struct dcss_segment, list); diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c index b0e1ba5c4..c6c39d868 100644 --- a/arch/s390/mm/ioremap.c +++ b/arch/s390/mm/ioremap.c @@ -134,5 +134,5 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag void iounmap(void *addr) { if (addr > high_memory) - return vfree(addr); + vfree(addr); } diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index 0b29e5fa1..76f53648c 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -22,6 +22,6 @@ EXPORT_SYMBOL(init_task); * in etrap.S which assumes it. */ union thread_union init_thread_union - __attribute__((section (".text"))) + __attribute__((section (".text,#alloc"))) __attribute__((aligned (THREAD_SIZE))) = { INIT_THREAD_INFO(init_task) }; diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 810a7ed25..45469d2f6 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -174,7 +174,7 @@ static inline int srmmu_pmd_present(pmd_t pmd) static inline void srmmu_pmd_clear(pmd_t *pmdp) { int i; - for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) + for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) srmmu_set_pte((pte_t *)&pmdp->pmdv[i], __pte(0)); } @@ -234,9 +234,9 @@ static void srmmu_pmd_set(pmd_t *pmdp, pte_t *ptep) int i; ptp = __nocache_pa((unsigned long) ptep) >> 4; - for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) { + for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); - ptp += (SRMMU_PTRS_PER_PTE*sizeof(pte_t) >> 4); + ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); } } @@ -246,9 +246,9 @@ static void srmmu_pmd_populate(pmd_t *pmdp, struct page *ptep) int i; ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */ - for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) { + for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); - ptp += (SRMMU_PTRS_PER_PTE*sizeof(pte_t) >> 4); + ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); } } @@ -263,7 +263,7 @@ extern inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long addre static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address) { return (pmd_t *) srmmu_pgd_page(*dir) + - ((address >> SRMMU_PMD_SHIFT_SOFT) & (SRMMU_PTRS_PER_PMD_SOFT - 1)); + ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); } /* Find an entry in the third-level page table.. */ @@ -273,7 +273,7 @@ static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) pte = __nocache_va((dir->pmdv[0] & SRMMU_PTD_PMASK) << 4); return (pte_t *) pte + - ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE_SOFT - 1)); + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); } static unsigned long srmmu_swp_type(swp_entry_t entry) @@ -487,7 +487,7 @@ static void srmmu_pmd_free(pmd_t * pmd) static pte_t * srmmu_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { - return (pte_t *)srmmu_get_nocache(SRMMU_PTE_SZ_SOFT, SRMMU_PTE_SZ_SOFT); + return (pte_t *)srmmu_get_nocache(PTE_SIZE, PTE_SIZE); } static struct page * @@ -502,7 +502,7 @@ srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address) static void srmmu_free_pte_fast(pte_t *pte) { - srmmu_free_nocache((unsigned long)pte, SRMMU_PTE_SZ_SOFT); + srmmu_free_nocache((unsigned long)pte, PTE_SIZE); } static void srmmu_pte_free(struct page *pte) @@ -514,7 +514,7 @@ static void srmmu_pte_free(struct page *pte) BUG(); p = page_to_pfn(pte) << PAGE_SHIFT; /* Physical address */ p = (unsigned long) __nocache_va(p); /* Nocached virtual */ - srmmu_free_nocache(p, SRMMU_PTE_SZ_SOFT); + srmmu_free_nocache(p, PTE_SIZE); } /* @@ -829,7 +829,7 @@ static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; - start &= SRMMU_PMD_MASK; + start &= SRMMU_REAL_PMD_MASK; while(start < end) { faddr = (start + (0x10000 - 0x100)); goto inside; @@ -849,7 +849,7 @@ static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f), "r" (g)); } while (faddr != start); - start += SRMMU_PMD_SIZE; + start += SRMMU_REAL_PMD_SIZE; } srmmu_set_context(octx); local_irq_restore(flags); @@ -1067,16 +1067,15 @@ void __init srmmu_early_allocate_ptable_skeleton(unsigned long start, unsigned l } pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { - ptep = (pte_t *)__srmmu_get_nocache(SRMMU_PTE_SZ_SOFT, - SRMMU_PTE_SZ_SOFT); + ptep = (pte_t *)__srmmu_get_nocache(PTE_SIZE, PTE_SIZE); if (ptep == NULL) early_pgtable_allocfail("pte"); - memset(__nocache_fix(ptep), 0, SRMMU_PTE_SZ_SOFT); + memset(__nocache_fix(ptep), 0, PTE_SIZE); srmmu_pmd_set(__nocache_fix(pmdp), ptep); } - if (start > (0xffffffffUL - SRMMU_PMD_SIZE_SOFT)) + if (start > (0xffffffffUL - PMD_SIZE)) break; - start = (start + SRMMU_PMD_SIZE_SOFT) & SRMMU_PMD_MASK_SOFT; + start = (start + PMD_SIZE) & PMD_MASK; } } @@ -1097,16 +1096,16 @@ void __init srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long en } pmdp = srmmu_pmd_offset(pgdp, start); if(srmmu_pmd_none(*pmdp)) { - ptep = (pte_t *) __srmmu_get_nocache(SRMMU_PTE_SZ_SOFT, - SRMMU_PTE_SZ_SOFT); + ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, + PTE_SIZE); if (ptep == NULL) early_pgtable_allocfail("pte"); - memset(ptep, 0, SRMMU_PTE_SZ_SOFT); + memset(ptep, 0, PTE_SIZE); srmmu_pmd_set(pmdp, ptep); } - if (start > (0xffffffffUL - SRMMU_PMD_SIZE_SOFT)) + if (start > (0xffffffffUL - PMD_SIZE)) break; - start = (start + SRMMU_PMD_SIZE_SOFT) & SRMMU_PMD_MASK_SOFT; + start = (start + PMD_SIZE) & PMD_MASK; } } @@ -1136,8 +1135,8 @@ void __init srmmu_inherit_prom_mappings(unsigned long start,unsigned long end) /* A red snapper, see what it really is. */ what = 0; - if(!(start & ~(SRMMU_PMD_MASK))) { - if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_PMD_SIZE) == prompte) + if(!(start & ~(SRMMU_REAL_PMD_MASK))) { + if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_REAL_PMD_SIZE) == prompte) what = 1; } @@ -1162,11 +1161,11 @@ void __init srmmu_inherit_prom_mappings(unsigned long start,unsigned long end) } pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { - ptep = (pte_t *) __srmmu_get_nocache(SRMMU_PTE_SZ_SOFT, - SRMMU_PTE_SZ_SOFT); + ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, + PTE_SIZE); if (ptep == NULL) early_pgtable_allocfail("pte"); - memset(__nocache_fix(ptep), 0, SRMMU_PTE_SZ_SOFT); + memset(__nocache_fix(ptep), 0, PTE_SIZE); srmmu_pmd_set(__nocache_fix(pmdp), ptep); } if(what == 1) { @@ -1176,9 +1175,9 @@ void __init srmmu_inherit_prom_mappings(unsigned long start,unsigned long end) * good hardware PTE piece. Alternatives seem worse. */ unsigned int x; /* Index of HW PMD in soft cluster */ - x = (start >> SRMMU_PMD_SHIFT) & 15; + x = (start >> PMD_SHIFT) & 15; *(unsigned long *)__nocache_fix(&pmdp->pmdv[x]) = prompte; - start += SRMMU_PMD_SIZE; + start += SRMMU_REAL_PMD_SIZE; continue; } ptep = srmmu_pte_offset(__nocache_fix(pmdp), start); @@ -2139,16 +2138,11 @@ void __init ld_mmu_srmmu(void) extern void ld_mmu_iounit(void); extern void ___xchg32_sun4md(void); - BTFIXUPSET_SIMM13(pmd_shift, SRMMU_PMD_SHIFT_SOFT); - BTFIXUPSET_SETHI(pmd_size, SRMMU_PMD_SIZE_SOFT); - BTFIXUPSET_SETHI(pmd_mask, SRMMU_PMD_MASK_SOFT); - BTFIXUPSET_SIMM13(pgdir_shift, SRMMU_PGDIR_SHIFT); BTFIXUPSET_SETHI(pgdir_size, SRMMU_PGDIR_SIZE); BTFIXUPSET_SETHI(pgdir_mask, SRMMU_PGDIR_MASK); - BTFIXUPSET_SIMM13(ptrs_per_pte, SRMMU_PTRS_PER_PTE_SOFT); - BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD_SOFT); + BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD); BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD); BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE)); diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 4b9fc1d67..f169a4838 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -2137,14 +2137,10 @@ void __init ld_mmu_sun4c(void) printk("Loading sun4c MMU routines\n"); /* First the constants */ - BTFIXUPSET_SIMM13(pmd_shift, SUN4C_PMD_SHIFT); - BTFIXUPSET_SETHI(pmd_size, SUN4C_PMD_SIZE); - BTFIXUPSET_SETHI(pmd_mask, SUN4C_PMD_MASK); BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT); BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE); BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK); - BTFIXUPSET_SIMM13(ptrs_per_pte, SUN4C_PTRS_PER_PTE); BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD); BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD); BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE); diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 6e39a101f..2296525af 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c @@ -243,8 +243,9 @@ int chmc_getunumber(int syndrome_code, static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) { unsigned long ret; + int this_cpu = get_cpu(); - if (mp->portid == smp_processor_id()) { + if (mp->portid == this_cpu) { __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (ret) : "r" (offset), "i" (ASI_MCU_CTRL_REG)); @@ -254,6 +255,8 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) : "r" (mp->regs + offset), "i" (ASI_PHYS_BYPASS_EC_E)); } + put_cpu(); + return ret; } diff --git a/arch/sparc64/lib/find_bit.c b/arch/sparc64/lib/find_bit.c new file mode 100644 index 000000000..420dfbafd --- /dev/null +++ b/arch/sparc64/lib/find_bit.c @@ -0,0 +1,125 @@ +#include + +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = addr + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp &= (~0UL << offset); + if (size < 64) + goto found_first; + if (tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if ((tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= (~0UL >> (64 - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +/* find_next_zero_bit() finds the first zero bit in a bit string of length + * 'size' bits, starting the search at bit 'offset'. This is largely based + * on Linus's ALPHA routines, which are pretty portable BTW. + */ + +unsigned long find_next_zero_bit(unsigned long *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = addr + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (64-offset); + if (size < 64) + goto found_first; + if (~tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ +found_middle: + return result + ffz(tmp); +} + +unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = addr + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if(offset) { + tmp = __swab64p(p++); + tmp |= (~0UL >> (64-offset)); + if(size < 64) + goto found_first; + if(~tmp) + goto found_middle; + size -= 64; + result += 64; + } + while(size & ~63) { + if(~(tmp = __swab64p(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if(!size) + return result; + tmp = __swab64p(p); +found_first: + tmp |= (~0UL << size); + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ +found_middle: + return result + ffz(tmp); +} diff --git a/arch/sparc64/lib/splock.S b/arch/sparc64/lib/splock.S new file mode 100644 index 000000000..d17a3badd --- /dev/null +++ b/arch/sparc64/lib/splock.S @@ -0,0 +1,23 @@ +/* splock.S: Spinlock primitives too large to inline. + * + * Copyright (C) 2004 David S. Miller (davem@redhat.com) + */ + + .text + .align 64 + + .globl _raw_spin_lock_flags +_raw_spin_lock_flags: /* %o0 = lock_ptr, %o1 = irq_flags */ +1: ldstub [%o0], %g7 + brnz,pn %g7, 2f + membar #StoreLoad | #StoreStore + retl + nop + +2: rdpr %pil, %g2 ! Save PIL + wrpr %o1, %pil ! Set previous PIL +3: ldub [%o0], %g7 ! Spin on lock set + brnz,pt %g7, 3b + membar #LoadLoad + ba,pt %xcc, 1b ! Retry lock acquire + wrpr %g2, %pil ! Restore PIL diff --git a/arch/sparc64/math-emu/sfp-util.h b/arch/sparc64/math-emu/sfp-util.h index bdde3da0f..31e474738 100644 --- a/arch/sparc64/math-emu/sfp-util.h +++ b/arch/sparc64/math-emu/sfp-util.h @@ -11,106 +11,106 @@ #include #include -#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ - __asm__ ("addcc %4,%5,%1\n\ - add %2,%3,%0\n\ - bcs,a,pn %%xcc, 1f\n\ - add %0, 1, %0\n\ - 1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ - : "r" ((UDItype)(ah)), \ - "r" ((UDItype)(bh)), \ - "r" ((UDItype)(al)), \ - "r" ((UDItype)(bl)) \ +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %4,%5,%1\n\t" \ + "add %2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "add %0, 1, %0\n" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl)) \ : "cc") -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - __asm__ ("subcc %4,%5,%1\n\ - sub %2,%3,%0\n\ - bcs,a,pn %%xcc, 1f\n\ - sub %0, 1, %0\n\ - 1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ - : "r" ((UDItype)(ah)), \ - "r" ((UDItype)(bh)), \ - "r" ((UDItype)(al)), \ - "r" ((UDItype)(bl)) \ +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %4,%5,%1\n\t" \ + "sub %2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "sub %0, 1, %0\n" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl)) \ : "cc") -#define umul_ppmm(wh, wl, u, v) \ - do { \ - UDItype tmp1, tmp2, tmp3, tmp4; \ - __asm__ __volatile__ ( \ - "srl %7,0,%3\n\ - mulx %3,%6,%1\n\ - srlx %6,32,%2\n\ - mulx %2,%3,%4\n\ - sllx %4,32,%5\n\ - srl %6,0,%3\n\ - sub %1,%5,%5\n\ - srlx %5,32,%5\n\ - addcc %4,%5,%4\n\ - srlx %7,32,%5\n\ - mulx %3,%5,%3\n\ - mulx %2,%5,%5\n\ - sethi %%hi(0x80000000),%2\n\ - addcc %4,%3,%4\n\ - srlx %4,32,%4\n\ - add %2,%2,%2\n\ - movcc %%xcc,%%g0,%2\n\ - addcc %5,%4,%5\n\ - sllx %3,32,%3\n\ - add %1,%3,%1\n\ - add %5,%2,%0" \ - : "=r" ((UDItype)(wh)), \ - "=&r" ((UDItype)(wl)), \ - "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ - : "r" ((UDItype)(u)), \ - "r" ((UDItype)(v)) \ - : "cc"); \ +#define umul_ppmm(wh, wl, u, v) \ + do { \ + UDItype tmp1, tmp2, tmp3, tmp4; \ + __asm__ __volatile__ ( \ + "srl %7,0,%3\n\t" \ + "mulx %3,%6,%1\n\t" \ + "srlx %6,32,%2\n\t" \ + "mulx %2,%3,%4\n\t" \ + "sllx %4,32,%5\n\t" \ + "srl %6,0,%3\n\t" \ + "sub %1,%5,%5\n\t" \ + "srlx %5,32,%5\n\t" \ + "addcc %4,%5,%4\n\t" \ + "srlx %7,32,%5\n\t" \ + "mulx %3,%5,%3\n\t" \ + "mulx %2,%5,%5\n\t" \ + "sethi %%hi(0x80000000),%2\n\t" \ + "addcc %4,%3,%4\n\t" \ + "srlx %4,32,%4\n\t" \ + "add %2,%2,%2\n\t" \ + "movcc %%xcc,%%g0,%2\n\t" \ + "addcc %5,%4,%5\n\t" \ + "sllx %3,32,%3\n\t" \ + "add %1,%3,%1\n\t" \ + "add %5,%2,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)), \ + "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v)) \ + : "cc"); \ } while (0) -#define udiv_qrnnd(q, r, n1, n0, d) \ - do { \ - UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ - __d1 = (d >> 32); \ - __d0 = (USItype)d; \ - \ - __r1 = (n1) % __d1; \ - __q1 = (n1) / __d1; \ - __m = (UWtype) __q1 * __d0; \ - __r1 = (__r1 << 32) | (n0 >> 32); \ - if (__r1 < __m) \ - { \ - __q1--, __r1 += (d); \ - if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \ - if (__r1 < __m) \ - __q1--, __r1 += (d); \ - } \ - __r1 -= __m; \ - \ - __r0 = __r1 % __d1; \ - __q0 = __r1 / __d1; \ - __m = (UWtype) __q0 * __d0; \ - __r0 = (__r0 << 32) | ((USItype)n0); \ - if (__r0 < __m) \ - { \ - __q0--, __r0 += (d); \ - if (__r0 >= (d)) \ - if (__r0 < __m) \ - __q0--, __r0 += (d); \ - } \ - __r0 -= __m; \ - \ - (q) = (UWtype) (__q1 << 32) | __q0; \ - (r) = __r0; \ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = (d >> 32); \ + __d0 = (USItype)d; \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = (__r1 << 32) | (n0 >> 32); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = (__r0 << 32) | ((USItype)n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) (__q1 << 32) | __q0; \ + (r) = __r0; \ } while (0) #define UDIV_NEEDS_NORMALIZATION 1 -#define abort() \ +#define abort() \ return 0 #ifdef __BIG_ENDIAN diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 348f206f0..5fc4644aa 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -207,14 +207,21 @@ outret: return insn; } -static void do_fault_siginfo(int code, int sig, unsigned long address) +extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); + +static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, + unsigned int insn, int fault_code) { siginfo_t info; info.si_code = code; info.si_signo = sig; info.si_errno = 0; - info.si_addr = (void *) address; + if (fault_code & FAULT_CODE_ITLB) + info.si_addr = (void *) regs->tpc; + else + info.si_addr = (void *) + compute_effective_address(regs, insn, 0); info.si_trapno = 0; force_sig_info(sig, &info, current); } @@ -295,7 +302,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, /* The si_code was set to make clear whether * this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - do_fault_siginfo(si_code, SIGSEGV, address); + do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); return; } @@ -471,7 +478,7 @@ do_sigbus: * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - do_fault_siginfo(BUS_ADRERR, SIGBUS, address); + do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); /* Kernel mode? Handle exceptions or die */ if (regs->tstate & TSTATE_PRIV) diff --git a/arch/x86_64/kernel/domain.c b/arch/x86_64/kernel/domain.c new file mode 100644 index 000000000..0694958c7 --- /dev/null +++ b/arch/x86_64/kernel/domain.c @@ -0,0 +1,93 @@ +#include +#include + +/* Don't do any NUMA setup on Opteron right now. They seem to be + better off with flat scheduling. This is just for SMT. */ + +#ifdef CONFIG_SCHED_SMT + +static struct sched_group sched_group_cpus[NR_CPUS]; +static struct sched_group sched_group_phys[NR_CPUS]; +static DEFINE_PER_CPU(struct sched_domain, cpu_domains); +static DEFINE_PER_CPU(struct sched_domain, phys_domains); +__init void arch_init_sched_domains(void) +{ + int i; + struct sched_group *first = NULL, *last = NULL; + + /* Set up domains */ + for_each_cpu(i) { + struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); + struct sched_domain *phys_domain = &per_cpu(phys_domains, i); + + *cpu_domain = SD_SIBLING_INIT; + /* Disable SMT NICE for CMP */ + /* RED-PEN use a generic flag */ + if (cpu_data[i].x86_vendor == X86_VENDOR_AMD) + cpu_domain->flags &= ~SD_SHARE_CPUPOWER; + cpu_domain->span = cpu_sibling_map[i]; + cpu_domain->parent = phys_domain; + cpu_domain->groups = &sched_group_cpus[i]; + + *phys_domain = SD_CPU_INIT; + phys_domain->span = cpu_possible_map; + phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)]; + } + + /* Set up CPU (sibling) groups */ + for_each_cpu(i) { + struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); + int j; + first = last = NULL; + + if (i != first_cpu(cpu_domain->span)) + continue; + + for_each_cpu_mask(j, cpu_domain->span) { + struct sched_group *cpu = &sched_group_cpus[j]; + + cpus_clear(cpu->cpumask); + cpu_set(j, cpu->cpumask); + cpu->cpu_power = SCHED_LOAD_SCALE; + + if (!first) + first = cpu; + if (last) + last->next = cpu; + last = cpu; + } + last->next = first; + } + + first = last = NULL; + /* Set up physical groups */ + for_each_cpu(i) { + struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); + struct sched_group *cpu = &sched_group_phys[i]; + + if (i != first_cpu(cpu_domain->span)) + continue; + + cpu->cpumask = cpu_domain->span; + /* + * Make each extra sibling increase power by 10% of + * the basic CPU. This is very arbitrary. + */ + cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10; + + if (!first) + first = cpu; + if (last) + last->next = cpu; + last = cpu; + } + last->next = first; + + mb(); + for_each_cpu(i) { + struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i); + cpu_attach_domain(cpu_domain, i); + } +} + +#endif diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index e5fd0d445..2cdf34b99 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -211,7 +211,8 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) int unhandled_signal(struct task_struct *tsk, int sig) { /* Warn for strace, but not for gdb */ - if ((tsk->ptrace & (PT_PTRACED|PT_TRACESYSGOOD)) == PT_PTRACED) + if (!test_ti_thread_flag(tsk->thread_info, TIF_SYSCALL_TRACE) && + (tsk->ptrace & PT_PTRACED)) return 0; return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); @@ -374,7 +375,7 @@ bad_area_nosemaphore: (address >> 32)) return; - if (exception_trace && !unhandled_signal(tsk, SIGSEGV)) { + if (exception_trace && unhandled_signal(tsk, SIGSEGV)) { printk(KERN_INFO "%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n", tsk->comm, tsk->pid, address, regs->rip, @@ -423,8 +424,9 @@ no_context: printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at %016lx RIP: \n",address); + printk(" at %016lx RIP: \n" KERN_ALERT,address); printk_address(regs->rip); + printk("\n"); dump_pagetable(address); __die("Oops", regs, error_code); /* Executive summary in case the body of the oops scrolled away */ diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index e891e9dc3..36743bf53 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -124,7 +124,7 @@ void __init setup_node_zones(int nodeid) start_pfn = node_start_pfn(nodeid); end_pfn = node_end_pfn(nodeid); - printk(KERN_INFO "setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn); + Dprintk(KERN_INFO "setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn); /* All nodes > 0 have a zero length zone DMA */ dma_end_pfn = __pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT; diff --git a/crypto/digest.c b/crypto/digest.c index 30dabe203..d9b6ac9db 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -27,13 +27,28 @@ static void update(struct crypto_tfm *tfm, struct scatterlist *sg, unsigned int nsg) { unsigned int i; - + for (i = 0; i < nsg; i++) { - char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; - tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), - p, sg[i].length); - crypto_kunmap(p, 0); - crypto_yield(tfm); + + struct page *pg = sg[i].page; + unsigned int offset = sg[i].offset; + unsigned int l = sg[i].length; + + do { + unsigned int bytes_from_page = min(l, ((unsigned int) + (PAGE_SIZE)) - + offset); + char *p = crypto_kmap(pg, 0) + offset; + + tfm->__crt_alg->cra_digest.dia_update + (crypto_tfm_ctx(tfm), p, + bytes_from_page); + crypto_kunmap(p, 0); + crypto_yield(tfm); + offset = 0; + pg++; + l -= bytes_from_page; + } while (l > 0); } } diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index b293bb7f9..c26a12e56 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1706,105 +1706,108 @@ static void destroy_queues (amb_dev * dev) { } /********** basic loader commands and error handling **********/ +// centisecond timeouts - guessing away here +static unsigned int command_timeouts [] = { + [host_memory_test] = 15, + [read_adapter_memory] = 2, + [write_adapter_memory] = 2, + [adapter_start] = 50, + [get_version_number] = 10, + [interrupt_host] = 1, + [flash_erase_sector] = 1, + [adap_download_block] = 1, + [adap_erase_flash] = 1, + [adap_run_in_iram] = 1, + [adap_end_download] = 1 +}; + + +unsigned int command_successes [] = { + [host_memory_test] = COMMAND_PASSED_TEST, + [read_adapter_memory] = COMMAND_READ_DATA_OK, + [write_adapter_memory] = COMMAND_WRITE_DATA_OK, + [adapter_start] = COMMAND_COMPLETE, + [get_version_number] = COMMAND_COMPLETE, + [interrupt_host] = COMMAND_COMPLETE, + [flash_erase_sector] = COMMAND_COMPLETE, + [adap_download_block] = COMMAND_COMPLETE, + [adap_erase_flash] = COMMAND_COMPLETE, + [adap_run_in_iram] = COMMAND_COMPLETE, + [adap_end_download] = COMMAND_COMPLETE +}; + +static int decode_loader_result (loader_command cmd, u32 result) +{ + int res; + const char *msg; + + if (result == command_successes[cmd]) + return 0; + + switch (result) { + case BAD_COMMAND: + res = -EINVAL; + msg = "bad command"; + break; + case COMMAND_IN_PROGRESS: + res = -ETIMEDOUT; + msg = "command in progress"; + break; + case COMMAND_PASSED_TEST: + res = 0; + msg = "command passed test"; + break; + case COMMAND_FAILED_TEST: + res = -EIO; + msg = "command failed test"; + break; + case COMMAND_READ_DATA_OK: + res = 0; + msg = "command read data ok"; + break; + case COMMAND_READ_BAD_ADDRESS: + res = -EINVAL; + msg = "command read bad address"; + break; + case COMMAND_WRITE_DATA_OK: + res = 0; + msg = "command write data ok"; + break; + case COMMAND_WRITE_BAD_ADDRESS: + res = -EINVAL; + msg = "command write bad address"; + break; + case COMMAND_WRITE_FLASH_FAILURE: + res = -EIO; + msg = "command write flash failure"; + break; + case COMMAND_COMPLETE: + res = 0; + msg = "command complete"; + break; + case COMMAND_FLASH_ERASE_FAILURE: + res = -EIO; + msg = "command flash erase failure"; + break; + case COMMAND_WRITE_BAD_DATA: + res = -EINVAL; + msg = "command write bad data"; + break; + default: + res = -EINVAL; + msg = "unknown error"; + PRINTD (DBG_LOAD|DBG_ERR, + "decode_loader_result got %d=%x !", + result, result); + break; + } + + PRINTK (KERN_ERR, "%s", msg); + return res; +} static int __init do_loader_command (volatile loader_block * lb, const amb_dev * dev, loader_command cmd) { - // centisecond timeouts - guessing away here - unsigned int command_timeouts [] = { - [host_memory_test] = 15, - [read_adapter_memory] = 2, - [write_adapter_memory] = 2, - [adapter_start] = 50, - [get_version_number] = 10, - [interrupt_host] = 1, - [flash_erase_sector] = 1, - [adap_download_block] = 1, - [adap_erase_flash] = 1, - [adap_run_in_iram] = 1, - [adap_end_download] = 1 - }; - - unsigned int command_successes [] = { - [host_memory_test] = COMMAND_PASSED_TEST, - [read_adapter_memory] = COMMAND_READ_DATA_OK, - [write_adapter_memory] = COMMAND_WRITE_DATA_OK, - [adapter_start] = COMMAND_COMPLETE, - [get_version_number] = COMMAND_COMPLETE, - [interrupt_host] = COMMAND_COMPLETE, - [flash_erase_sector] = COMMAND_COMPLETE, - [adap_download_block] = COMMAND_COMPLETE, - [adap_erase_flash] = COMMAND_COMPLETE, - [adap_run_in_iram] = COMMAND_COMPLETE, - [adap_end_download] = COMMAND_COMPLETE - }; - - int decode_loader_result (loader_command cmd, u32 result) { - int res; - const char * msg; - - if (result == command_successes[cmd]) - return 0; - - switch (result) { - case BAD_COMMAND: - res = -EINVAL; - msg = "bad command"; - break; - case COMMAND_IN_PROGRESS: - res = -ETIMEDOUT; - msg = "command in progress"; - break; - case COMMAND_PASSED_TEST: - res = 0; - msg = "command passed test"; - break; - case COMMAND_FAILED_TEST: - res = -EIO; - msg = "command failed test"; - break; - case COMMAND_READ_DATA_OK: - res = 0; - msg = "command read data ok"; - break; - case COMMAND_READ_BAD_ADDRESS: - res = -EINVAL; - msg = "command read bad address"; - break; - case COMMAND_WRITE_DATA_OK: - res = 0; - msg = "command write data ok"; - break; - case COMMAND_WRITE_BAD_ADDRESS: - res = -EINVAL; - msg = "command write bad address"; - break; - case COMMAND_WRITE_FLASH_FAILURE: - res = -EIO; - msg = "command write flash failure"; - break; - case COMMAND_COMPLETE: - res = 0; - msg = "command complete"; - break; - case COMMAND_FLASH_ERASE_FAILURE: - res = -EIO; - msg = "command flash erase failure"; - break; - case COMMAND_WRITE_BAD_DATA: - res = -EINVAL; - msg = "command write bad data"; - break; - default: - res = -EINVAL; - msg = "unknown error"; - PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_result got %d=%x !", - result, result); - break; - } - - PRINTK (KERN_ERR, "%s", msg); - return res; - } unsigned long timeout; @@ -1930,6 +1933,11 @@ static int __init loader_start (loader_block * lb, /********** reset card **********/ +static inline void sf (const char * msg) +{ + PRINTK (KERN_ERR, "self-test failed: %s", msg); +} + static int amb_reset (amb_dev * dev, int diags) { u32 word; @@ -1974,9 +1982,6 @@ static int amb_reset (amb_dev * dev, int diags) { // XXX double check byte-order word = rd_mem (dev, offsetof(amb_mem, mb.loader.result)); if (word & SELF_TEST_FAILURE) { - void sf (const char * msg) { - PRINTK (KERN_ERR, "self-test failed: %s", msg); - } if (word & GPINT_TST_FAILURE) sf ("interrupt"); if (word & SUNI_DATA_PATTERN_FAILURE) @@ -2044,31 +2049,31 @@ static int __init ucode_init (loader_block * lb, amb_dev * dev) { } /********** give adapter parameters **********/ + +static inline u32 bus_addr(void * addr) { + return cpu_to_be32 (virt_to_bus (addr)); +} static int __init amb_talk (amb_dev * dev) { adap_talk_block a; unsigned char pool; unsigned long timeout; - u32 x (void * addr) { - return cpu_to_be32 (virt_to_bus (addr)); - } - PRINTD (DBG_FLOW, "amb_talk %p", dev); - a.command_start = x (dev->cq.ptrs.start); - a.command_end = x (dev->cq.ptrs.limit); - a.tx_start = x (dev->txq.in.start); - a.tx_end = x (dev->txq.in.limit); - a.txcom_start = x (dev->txq.out.start); - a.txcom_end = x (dev->txq.out.limit); + a.command_start = bus_addr (dev->cq.ptrs.start); + a.command_end = bus_addr (dev->cq.ptrs.limit); + a.tx_start = bus_addr (dev->txq.in.start); + a.tx_end = bus_addr (dev->txq.in.limit); + a.txcom_start = bus_addr (dev->txq.out.start); + a.txcom_end = bus_addr (dev->txq.out.limit); for (pool = 0; pool < NUM_RX_POOLS; ++pool) { // the other "a" items are set up by the adapter - a.rec_struct[pool].buffer_start = x (dev->rxq[pool].in.start); - a.rec_struct[pool].buffer_end = x (dev->rxq[pool].in.limit); - a.rec_struct[pool].rx_start = x (dev->rxq[pool].out.start); - a.rec_struct[pool].rx_end = x (dev->rxq[pool].out.limit); + a.rec_struct[pool].buffer_start = bus_addr (dev->rxq[pool].in.start); + a.rec_struct[pool].buffer_end = bus_addr (dev->rxq[pool].in.limit); + a.rec_struct[pool].rx_start = bus_addr (dev->rxq[pool].out.start); + a.rec_struct[pool].rx_end = bus_addr (dev->rxq[pool].out.limit); a.rec_struct[pool].buffer_size = cpu_to_be32 (dev->rxq[pool].buffer_size); } @@ -2111,15 +2116,10 @@ static void __init amb_ucode_version (amb_dev * dev) { minor = be32_to_cpu (cmd.args.version.minor); PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor); } - -// get end station address -static void __init amb_esi (amb_dev * dev, u8 * esi) { - u32 lower4; - u16 upper2; - command cmd; - // swap bits within byte to get Ethernet ordering - u8 bit_swap (u8 byte) { +// swap bits within byte to get Ethernet ordering +u8 bit_swap (u8 byte) +{ const u8 swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, @@ -2127,7 +2127,13 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) { 0x3, 0xb, 0x7, 0xf }; return ((swap[byte & 0xf]<<4) | swap[byte>>4]); - } +} + +// get end station address +static void __init amb_esi (amb_dev * dev, u8 * esi) { + u32 lower4; + u16 upper2; + command cmd; cmd.request = cpu_to_be32 (SRB_GET_BIA); while (command_do (dev, &cmd)) { @@ -2155,29 +2161,31 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) { return; } + +static void fixup_plx_window (amb_dev *dev, loader_block *lb) +{ + // fix up the PLX-mapped window base address to match the block + unsigned long blb; + u32 mapreg; + blb = virt_to_bus(lb); + // the kernel stack had better not ever cross a 1Gb boundary! + mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10])); + mapreg &= ~onegigmask; + mapreg |= blb & onegigmask; + wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg); + return; +} -static int __init amb_init (amb_dev * dev) { +static int __init amb_init (amb_dev * dev) +{ loader_block lb; - void fixup_plx_window (void) { - // fix up the PLX-mapped window base address to match the block - unsigned long blb; - u32 mapreg; - blb = virt_to_bus (&lb); - // the kernel stack had better not ever cross a 1Gb boundary! - mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10])); - mapreg &= ~onegigmask; - mapreg |= blb & onegigmask; - wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg); - return; - } - u32 version; if (amb_reset (dev, 1)) { PRINTK (KERN_ERR, "card reset failed!"); } else { - fixup_plx_window (); + fixup_plx_window (dev, &lb); if (get_loader_version (&lb, dev, &version)) { PRINTK (KERN_INFO, "failed to get loader version"); @@ -2207,31 +2215,20 @@ static int __init amb_init (amb_dev * dev) { } /* amb_reset */ - return -1; + return -EINVAL; } -static int __init amb_probe (void) { - struct pci_dev * pci_dev; - int devs; - - void __init do_pci_device (void) { - amb_dev * dev; - - // read resources from PCI configuration space - u8 irq = pci_dev->irq; - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0)); - u32 iobase = pci_resource_start (pci_dev, 1); - - void setup_dev (void) { +static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) +{ unsigned char pool; memset (dev, 0, sizeof(amb_dev)); // set up known dev items straight away dev->pci_dev = pci_dev; - dev->iobase = iobase; - dev->irq = irq; - dev->membase = membase; + dev->iobase = pci_resource_start (pci_dev, 1); + dev->irq = pci_dev->irq; + dev->membase = bus_to_virt(pci_resource_start(pci_dev, 0)); // flags (currently only dead) dev->flags = 0; @@ -2258,101 +2255,125 @@ static int __init amb_probe (void) { spin_lock_init (&dev->txq.lock); for (pool = 0; pool < NUM_RX_POOLS; ++pool) spin_lock_init (&dev->rxq[pool].lock); - } - - void setup_pci_dev (void) { - unsigned char lat; - - /* XXX check return value */ - pci_enable_device (pci_dev); +} - // enable bus master accesses - pci_set_master (pci_dev); - - // frobnicate latency (upwards, usually) - pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); - if (pci_lat) { - PRINTD (DBG_INIT, "%s PCI latency timer from %hu to %hu", - "changing", lat, pci_lat); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat); - } else if (lat < MIN_PCI_LATENCY) { - PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu", - "increasing", lat, MIN_PCI_LATENCY); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); - } - } - - PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" - " IO %x, IRQ %u, MEM %p", iobase, irq, membase); - - // check IO region - if (!request_region (iobase, AMB_EXTENT, DEV_LABEL)) { - PRINTK (KERN_ERR, "IO range already in use!"); - return; - } - - dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); - if (!dev) { - // perhaps we should be nice: deregister all adapters and abort? - PRINTK (KERN_ERR, "out of memory!"); - release_region (iobase, AMB_EXTENT); - return; - } - - setup_dev(); - - if (amb_init (dev)) { - PRINTK (KERN_ERR, "adapter initialisation failure"); - } else { +static int setup_pci_dev(struct pci_dev *pci_dev) +{ + unsigned char lat; + int ret; - setup_pci_dev(); + // enable bus master accesses + pci_set_master(pci_dev); - // grab (but share) IRQ and install handler - if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) { - PRINTK (KERN_ERR, "request IRQ failed!"); - // free_irq is at "endif" - } else { - + ret = pci_enable_device(pci_dev); + if (ret < 0) + goto out; + + // frobnicate latency (upwards, usually) + pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); + + if (!pci_lat) + pci_lat = (lat < MIN_PCI_LATENCY) ? MIN_PCI_LATENCY : lat; + + if (lat != pci_lat) { + PRINTK (KERN_INFO, "Changing PCI latency timer from %hu to %hu", + lat, pci_lat); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat); + } +out: + return ret; +} + +static int __init do_pci_device(struct pci_dev *pci_dev) +{ + amb_dev * dev; + int err; + + // read resources from PCI configuration space + u8 irq = pci_dev->irq; + u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0)); + u32 iobase = pci_resource_start (pci_dev, 1); + + PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" + " IO %x, IRQ %u, MEM %p", iobase, irq, membase); + + // check IO region + err = pci_request_region(pci_dev, 1, DEV_LABEL); + if (err < 0) { + PRINTK (KERN_ERR, "IO range already in use!"); + goto out; + } + + dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); + if (!dev) { + PRINTK (KERN_ERR, "out of memory!"); + err = -ENOMEM; + goto out_release; + } + + setup_dev(dev, pci_dev); + + err = amb_init(dev); + if (err < 0) { + PRINTK (KERN_ERR, "adapter initialisation failure"); + goto out_free; + } + + err = setup_pci_dev(pci_dev); + if (err < 0) + goto out_reset; + + // grab (but share) IRQ and install handler + err = request_irq(irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev); + if (err < 0) { + PRINTK (KERN_ERR, "request IRQ failed!"); + goto out_disable; + } + dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL); if (!dev->atm_dev) { - PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); - } else { - - PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", - dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; - - // register our address - amb_esi (dev, dev->atm_dev->esi); - - // 0 bits for vpi, 10 bits for vci - dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; - dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; - - // update count and linked list - ++devs; - dev->prev = amb_devs; - amb_devs = dev; - - // enable host interrupts - interrupts_on (dev); - - // success - return; - - // not currently reached - atm_dev_deregister (dev->atm_dev); - } /* atm_dev_register */ - - free_irq (irq, dev); - } /* request_irq */ - - amb_reset (dev, 0); - } /* amb_init */ - - kfree (dev); - release_region (iobase, AMB_EXTENT); - } /* kmalloc, end-of-fn */ + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + err = -EINVAL; + goto out_free_irq; + } + + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); + dev->atm_dev->dev_data = (void *) dev; + + // register our address + amb_esi (dev, dev->atm_dev->esi); + + // 0 bits for vpi, 10 bits for vci + dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; + dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; + + // update linked list + dev->prev = amb_devs; + amb_devs = dev; + + // enable host interrupts + interrupts_on (dev); + +out: + return err; + +out_free_irq: + free_irq(irq, dev); +out_disable: + pci_disable_device(pci_dev); +out_reset: + amb_reset(dev, 0); +out_free: + kfree(dev); +out_release: + pci_release_region(pci_dev, 1); + goto out; +} + +static int __init amb_probe (void) { + struct pci_dev * pci_dev; + int devs; PRINTD (DBG_FLOW, "amb_probe"); @@ -2360,8 +2381,11 @@ static int __init amb_probe (void) { pci_dev = NULL; while ((pci_dev = pci_find_device (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, pci_dev) - )) - do_pci_device(); + )) { + if (do_pci_device(pci_dev) == 0) + devs++; + } + pci_dev = NULL; while ((pci_dev = pci_find_device @@ -2474,7 +2498,10 @@ static void __exit amb_module_exit (void) { del_timer_sync(&housekeeping); while (amb_devs) { + struct pci_dev *pdev; + dev = amb_devs; + pdev = dev->pci_dev; amb_devs = dev->prev; PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev); @@ -2482,11 +2509,12 @@ static void __exit amb_module_exit (void) { drain_rx_pools (dev); interrupts_off (dev); amb_reset (dev, 0); + free_irq (dev->irq, dev); + pci_disable_device (pdev); destroy_queues (dev); atm_dev_deregister (dev->atm_dev); - free_irq (dev->irq, dev); - release_region (dev->iobase, AMB_EXTENT); kfree (dev); + pci_release_region (pdev, 1); } return; diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index aa1cbe395..0572f724b 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -152,7 +152,7 @@ static void atmtcp_v_close(struct atm_vcc *vcc) } -static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { struct atm_cirange ci; struct atm_vcc *vcc; @@ -161,7 +161,7 @@ static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) int i; if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD; - if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT; + if (copy_from_user(&ci, arg,sizeof(ci))) return -EFAULT; if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index b76058900..8b137034d 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1968,7 +1968,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) } -static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { struct eni_dev *eni_dev = ENI_DEV(dev); @@ -1983,7 +1983,7 @@ static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) struct eni_multipliers mult; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(&mult,(void *) arg, + if (copy_from_user(&mult, arg, sizeof(struct eni_multipliers))) return -EFAULT; if ((mult.tx && mult.tx <= 100) || (mult.rx &&mult.rx <= 100) || @@ -1996,7 +1996,7 @@ static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) if (cmd == ATM_SETCIRANGE) { struct atm_cirange ci; - if (copy_from_user(&ci,(void *) arg,sizeof(struct atm_cirange))) + if (copy_from_user(&ci, arg,sizeof(struct atm_cirange))) return -EFAULT; if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && (ci.vci_bits == NR_VCI_LD || ci.vpi_bits == ATM_CI_MAX)) @@ -2009,14 +2009,14 @@ static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { return -EINVAL; } static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { return -EINVAL; } diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index f45adbb4c..025c692fd 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1220,7 +1220,7 @@ static int fs_send (struct atm_vcc *atm_vcc, struct sk_buff *skb) /* Some function placeholders for functions we don't yet support. */ #if 0 -static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { func_enter (); func_exit (); @@ -1229,7 +1229,7 @@ static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { func_enter (); func_exit (); @@ -1238,7 +1238,7 @@ static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname, static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { func_enter (); func_exit (); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 72123ecfb..ad746d981 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -134,7 +134,7 @@ static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $"; static int he_open(struct atm_vcc *vcc); static void he_close(struct atm_vcc *vcc); static int he_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs); static void he_tasklet(unsigned long data); static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); @@ -2809,7 +2809,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) } static int -he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg) +he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg) { unsigned long flags; struct he_dev *he_dev = HE_DEV(atm_dev); @@ -2821,8 +2821,8 @@ he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg) if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(®, (struct he_ioctl_reg *) arg, - sizeof(struct he_ioctl_reg))) + if (copy_from_user(®, arg, + sizeof(struct he_ioctl_reg))) return -EFAULT; spin_lock_irqsave(&he_dev->global_lock, flags); @@ -2848,7 +2848,7 @@ he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg) } spin_unlock_irqrestore(&he_dev->global_lock, flags); if (err == 0) - if (copy_to_user((struct he_ioctl_reg *) arg, ®, + if (copy_to_user(arg, ®, sizeof(struct he_ioctl_reg))) return -EFAULT; break; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 90e407a9a..a794610da 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -597,126 +597,112 @@ static inline u16 rx_q_entry_to_rx_channel (u32 x) { // p ranges from 1 to a power of 2 #define CR_MAXPEXP 4 - + static int make_rate (const hrz_dev * dev, u32 c, rounding r, - u16 * bits, unsigned int * actual) { - - // note: rounding the rate down means rounding 'p' up - - const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ; - - u32 div = CR_MIND; - u32 pre; + u16 * bits, unsigned int * actual) +{ + // note: rounding the rate down means rounding 'p' up + const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ; - // local fn to build the timer bits - int set_cr (void) { - // paranoia - if (div > CR_MAXD || (!pre) || pre > 1<> 1; - ++br_exp; - } - // (br >>br_exp) <> 1; + ++br_exp; + } + // (br >>br_exp) < CR_MAXD || (!pre) || pre > 1<> 1; - CLOCK_IT(); + CLOCK_IT(dev, ctrl); if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO) res |= (1 << (data_bits-1)); } ctrl &= ~(SEEPROM_SK | SEEPROM_CS); - WRITE_IT_WAIT(); + WRITE_IT_WAIT(dev, ctrl); return res; } diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index c95ca296b..c1fb6c710 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -141,7 +141,7 @@ static void idt77105_restart_timer_func(unsigned long dummy) } -static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero) +static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int zero) { unsigned long flags; struct idt77105_stats stats; @@ -188,7 +188,7 @@ static int set_loopback(struct atm_dev *dev,int mode) } -static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number); switch (cmd) { @@ -196,16 +196,15 @@ static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) if (!capable(CAP_NET_ADMIN)) return -EPERM; /* fall through */ case IDT77105_GETSTAT: - return fetch_stats(dev,(struct idt77105_stats *) arg, - cmd == IDT77105_GETSTATZ); + return fetch_stats(dev, arg, cmd == IDT77105_GETSTATZ); case ATM_SETLOOP: return set_loopback(dev,(int) (long) arg); case ATM_GETLOOP: - return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM, - (int *) arg) ? -EFAULT : 0; + (int __user *) arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 2b6b9c6eb..3c964ecfb 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2738,12 +2738,12 @@ static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) return 0; } -static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) { IA_CMDBUF ia_cmds; IADEV *iadev; int i, board; - u16 *tmps; + u16 __user *tmps; IF_EVENT(printk(">ia_ioctl\n");) if (cmd != IA_CMD) { if (!dev->phy->ioctl) return -EINVAL; @@ -2766,7 +2766,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) break; case MEMDUMP_SEGREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - tmps = (u16 *)ia_cmds.buf; + tmps = (u16 __user *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) if(put_user((u16)(readl(iadev->seg_reg+i) & 0xffff), tmps)) return -EFAULT; ia_cmds.status = 0; @@ -2774,7 +2774,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) break; case MEMDUMP_REASSREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - tmps = (u16 *)ia_cmds.buf; + tmps = (u16 __user *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) if(put_user((u16)(readl(iadev->reass_reg+i) & 0xffff), tmps)) return -EFAULT; ia_cmds.status = 0; @@ -2874,14 +2874,14 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) } static int ia_getsockopt(struct atm_vcc *vcc, int level, int optname, - void *optval, int optlen) + void __user *optval, int optlen) { IF_EVENT(printk(">ia_getsockopt\n");) return -EINVAL; } static int ia_setsockopt(struct atm_vcc *vcc, int level, int optname, - void *optval, int optlen) + void __user *optval, int optlen) { IF_EVENT(printk(">ia_setsockopt\n");) return -EINVAL; diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h index 1134bda43..92e514c79 100644 --- a/drivers/atm/iphase.h +++ b/drivers/atm/iphase.h @@ -141,7 +141,7 @@ typedef struct { int len; u32 maddr; int status; - void *buf; + void __user *buf; } IA_CMDBUF, *PIA_CMDBUF; /* cmds */ diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 5a7037af6..ac80b9efd 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -2435,7 +2435,7 @@ static int lanai_open(struct atm_vcc *atmvcc) #if 0 /* ioctl operations for card */ /* NOTE: these are all DEBUGGING ONLY currently */ -static int lanai_ioctl(struct atm_dev *atmdev, unsigned int cmd, void *arg) +static int lanai_ioctl(struct atm_dev *atmdev, unsigned int cmd, void __user *arg) { int result = 0; struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 11875f784..b63669c1f 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -239,7 +239,7 @@ static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb); static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb); static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb); static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page); -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); static void which_list(ns_dev *card, struct sk_buff *skb); static void ns_poll(unsigned long arg); static int ns_parse_mac(char *mac, unsigned char *esi); @@ -2765,7 +2765,7 @@ static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page) -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) { ns_dev *card; pool_levels pl; @@ -2776,7 +2776,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) switch (cmd) { case NS_GETPSTAT: - if (get_user(pl.buftype, &((pool_levels *) arg)->buftype)) + if (get_user(pl.buftype, &((pool_levels __user *) arg)->buftype)) return -EFAULT; switch (pl.buftype) { @@ -2812,7 +2812,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) return -ENOIOCTLCMD; } - if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) + if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl))) return (sizeof(pl)); else return -EFAULT; @@ -2820,7 +2820,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) case NS_SETBUFLEV: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl))) + if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl))) return -EFAULT; if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max) return -EINVAL; diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index e245e94bd..e5a0f5cbd 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -95,7 +95,7 @@ static void suni_hz(unsigned long from_timer) #undef ADD_LIMITED -static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) +static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero) { struct sonet_stats tmp; int error = 0; @@ -115,11 +115,11 @@ static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) } -static int change_diag(struct atm_dev *dev,void *arg,int set) +static int change_diag(struct atm_dev *dev,void __user *arg,int set) { int todo; - if (get_user(todo,(int *) arg)) return -EFAULT; + if (get_user(todo,(int __user *)arg)) return -EFAULT; HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8); HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP); HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3); @@ -128,14 +128,14 @@ static int change_diag(struct atm_dev *dev,void *arg,int set) HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS); HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS); HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS); - return put_user(todo,(int *) arg) ? -EFAULT : 0; + return put_user(todo,(int __user *)arg) ? -EFAULT : 0; } #undef HANDLE_FLAG -static int get_diag(struct atm_dev *dev,void *arg) +static int get_diag(struct atm_dev *dev,void __user *arg) { int set; @@ -148,7 +148,7 @@ static int get_diag(struct atm_dev *dev,void *arg) if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS; if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS; if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS; - return put_user(set,(int *) arg) ? -EFAULT : 0; + return put_user(set,(int __user *)arg) ? -EFAULT : 0; } @@ -175,13 +175,12 @@ static int set_loopback(struct atm_dev *dev,int mode) } -static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { switch (cmd) { case SONET_GETSTATZ: case SONET_GETSTAT: - return fetch_stats(dev,(struct sonet_stats *) arg, - cmd == SONET_GETSTATZ); + return fetch_stats(dev, arg, cmd == SONET_GETSTATZ); case SONET_SETDIAG: return change_diag(dev,arg,1); case SONET_CLRDIAG: @@ -192,18 +191,18 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) if (arg != SONET_FRAME_SONET) return -EINVAL; return 0; case SONET_GETFRAMING: - return put_user(SONET_FRAME_SONET,(int *) arg) ? + return put_user(SONET_FRAME_SONET,(int __user *)arg) ? -EFAULT : 0; case SONET_GETFRSENSE: return -EINVAL; case ATM_SETLOOP: return set_loopback(dev,(int) (long) arg); case ATM_GETLOOP: - return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, - (int *) arg) ? -EFAULT : 0; + (int __user *) arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index 0bc05c960..da33eaddc 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -37,7 +37,7 @@ struct uPD98402_priv { #define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg) -static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) +static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero) { struct sonet_stats tmp; int error = 0; @@ -83,7 +83,7 @@ static int set_framing(struct atm_dev *dev,unsigned char framing) } -static int get_sense(struct atm_dev *dev,u8 *arg) +static int get_sense(struct atm_dev *dev,u8 __user *arg) { unsigned long flags; unsigned char s[3]; @@ -132,29 +132,28 @@ static int set_loopback(struct atm_dev *dev,int mode) } -static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { switch (cmd) { case SONET_GETSTATZ: case SONET_GETSTAT: - return fetch_stats(dev,(struct sonet_stats *) arg, - cmd == SONET_GETSTATZ); + return fetch_stats(dev,arg, cmd == SONET_GETSTATZ); case SONET_SETFRAMING: return set_framing(dev,(int) (long) arg); case SONET_GETFRAMING: - return put_user(PRIV(dev)->framing,(int *) arg) ? + return put_user(PRIV(dev)->framing,(int __user *)arg) ? -EFAULT : 0; case SONET_GETFRSENSE: return get_sense(dev,arg); case ATM_SETLOOP: return set_loopback(dev,(int) (long) arg); case ATM_GETLOOP: - return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM | - ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0; + ATM_LM_RMT_PHY,(int __user *)arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 9027baa42..88d548a18 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1429,7 +1429,7 @@ static int zatm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags) } -static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { struct zatm_dev *zatm_dev; unsigned long flags; @@ -1445,7 +1445,7 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) int pool; if (get_user(pool, - &((struct zatm_pool_req *) arg)->pool_num)) + &((struct zatm_pool_req __user *) arg)->pool_num)) return -EFAULT; if (pool < 0 || pool > ZATM_LAST_POOL) return -EINVAL; @@ -1457,7 +1457,7 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) } spin_unlock_irqrestore(&zatm_dev->lock, flags); return copy_to_user( - &((struct zatm_pool_req *) arg)->info, + &((struct zatm_pool_req __user *) arg)->info, &info,sizeof(info)) ? -EFAULT : 0; } case ZATM_SETPOOL: @@ -1467,12 +1467,12 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) if (!capable(CAP_NET_ADMIN)) return -EPERM; if (get_user(pool, - &((struct zatm_pool_req *) arg)->pool_num)) + &((struct zatm_pool_req __user *) arg)->pool_num)) return -EFAULT; if (pool < 0 || pool > ZATM_LAST_POOL) return -EINVAL; if (copy_from_user(&info, - &((struct zatm_pool_req *) arg)->info, + &((struct zatm_pool_req __user *) arg)->info, sizeof(info))) return -EFAULT; if (!info.low_water) info.low_water = zatm_dev-> @@ -1504,14 +1504,14 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { return -EINVAL; } static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname, - void *optval,int optlen) + void __user *optval,int optlen) { return -EINVAL; } diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 676c07808..be8f8992a 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -1914,8 +1914,8 @@ typedef struct DAC960_V1_UserCommand unsigned char ControllerNumber; DAC960_V1_CommandMailbox_T CommandMailbox; int DataTransferLength; - void *DataTransferBuffer; - DAC960_V1_DCDB_T *DCDB; + void __user *DataTransferBuffer; + DAC960_V1_DCDB_T __user *DCDB; } DAC960_V1_UserCommand_T; @@ -1948,8 +1948,8 @@ typedef struct DAC960_V2_UserCommand DAC960_V2_CommandMailbox_T CommandMailbox; int DataTransferLength; int RequestSenseLength; - void *DataTransferBuffer; - void *RequestSenseBuffer; + void __user *DataTransferBuffer; + void __user *RequestSenseBuffer; } DAC960_V2_UserCommand_T; @@ -1980,7 +1980,7 @@ DAC960_V2_KernelCommand_T; typedef struct DAC960_V2_GetHealthStatus { unsigned char ControllerNumber; - DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer; + DAC960_V2_HealthStatusBuffer_T __user *HealthStatusBuffer; } DAC960_V2_GetHealthStatus_T; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b22099f1f..0d45b81e1 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -135,7 +135,6 @@ static int register_new_disk(ctlr_info_t *h); static void cciss_getgeometry(int cntl_num); -static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c); static void start_io( ctlr_info_t *h); static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, @@ -157,6 +156,36 @@ static struct block_device_operations cciss_fops = { .revalidate_disk= cciss_revalidate, }; +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline CommandList_struct *removeQ(CommandList_struct **Qptr, + CommandList_struct *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} +#ifdef CONFIG_PROC_FS + #include "cciss_scsi.c" /* For SCSI tape support */ /* @@ -167,7 +196,6 @@ static struct block_device_operations cciss_fops = { #define RAID_UNKNOWN 6 static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG", "UNKNOWN"}; -#ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_cciss; @@ -257,7 +285,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, } static int -cciss_proc_write(struct file *file, const char *buffer, +cciss_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned char cmd[80]; @@ -462,6 +490,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, ctlr_info_t *host = get_host(disk); drive_info_struct *drv = get_drv(disk); int ctlr = host->ctlr; + void __user *argp = (void __user *)arg; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg); @@ -478,8 +507,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, } else return -ENXIO; driver_geo.start= get_start_sect(inode->i_bdev); - if (copy_to_user((void *) arg, &driver_geo, - sizeof( struct hd_geometry))) + if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry))) return -EFAULT; return(0); } @@ -492,7 +520,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, pciinfo.bus = host->pdev->bus->number; pciinfo.dev_fn = host->pdev->devfn; pciinfo.board_id = host->board_id; - if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct ))) + if (copy_to_user(argp, &pciinfo, sizeof( cciss_pci_info_struct ))) return -EFAULT; return(0); } @@ -502,7 +530,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay); intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount); - if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct ))) + if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct ))) return -EFAULT; return(0); } @@ -514,7 +542,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct))) + if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct))) return -EFAULT; if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) @@ -550,7 +578,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; for(i=0;i<16;i++) NodeName[i] = readb(&host->cfgtable->ServerName[i]); - if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type))) + if (copy_to_user(argp, NodeName, sizeof( NodeName_type))) return -EFAULT; return(0); } @@ -563,7 +591,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type))) + if (copy_from_user(NodeName, argp, sizeof( NodeName_type))) return -EFAULT; spin_lock_irqsave(CCISS_LOCK(ctlr), flags); @@ -593,7 +621,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; heartbeat = readl(&host->cfgtable->HeartBeat); - if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type))) + if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type))) return -EFAULT; return(0); } @@ -603,7 +631,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; BusTypes = readl(&host->cfgtable->BusTypes); - if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) )) + if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) )) return -EFAULT; return(0); } @@ -614,7 +642,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; memcpy(firmware, host->firm_ver, 4); - if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type))) + if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type))) return -EFAULT; return(0); } @@ -624,7 +652,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!arg) return -EINVAL; - if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) )) + if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) )) return -EFAULT; return(0); } @@ -648,7 +676,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (disk->part[i]->nr_sects != 0) luninfo.num_parts++; } - if (copy_to_user((void *) arg, &luninfo, + if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct))) return -EFAULT; return(0); @@ -672,7 +700,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, if (!capable(CAP_SYS_RAWIO)) return -EPERM; - if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) )) + if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) )) return -EFAULT; if((iocommand.buf_size < 1) && (iocommand.Request.Type.Direction != XFER_NONE)) @@ -753,7 +781,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, /* Copy the error information out */ iocommand.error_info = *(c->err_info); - if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) + if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) ) { kfree(buff); cmd_free(host, c, 0); @@ -787,7 +815,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, DECLARE_COMPLETION(wait); __u32 left; __u32 sz; - BYTE *data_ptr; + BYTE __user *data_ptr; if (!arg) return -EINVAL; @@ -799,7 +827,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, status = -ENOMEM; goto cleanup1; } - if (copy_from_user(ioc, (void *) arg, sizeof(*ioc))) { + if (copy_from_user(ioc, argp, sizeof(*ioc))) { status = -EFAULT; goto cleanup1; } @@ -831,7 +859,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, goto cleanup1; } left = ioc->buf_size; - data_ptr = (BYTE *) ioc->buf; + data_ptr = ioc->buf; while (left) { sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; buff_size[sg_used] = sz; @@ -896,14 +924,14 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, } /* Copy the error information out */ ioc->error_info = *(c->err_info); - if (copy_to_user((void *) arg, ioc, sizeof(*ioc))) { + if (copy_to_user(argp, ioc, sizeof(*ioc))) { cmd_free(host, c, 0); status = -EFAULT; goto cleanup1; } if (ioc->Request.Type.Direction == XFER_READ) { /* Copy the data out of the buffer we created */ - BYTE *ptr = (BYTE *) ioc->buf; + BYTE __user *ptr = ioc->buf; for(i=0; i< sg_used; i++) { if (copy_to_user(ptr, buff[i], buff_size[i])) { cmd_free(host, c, 0); @@ -1685,35 +1713,6 @@ static ulong remap_pci_mem(ulong base, ulong size) return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); } -/* - * Enqueuing and dequeuing functions for cmdlists. - */ -static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) -{ - if (*Qptr == NULL) { - *Qptr = c; - c->next = c->prev = c; - } else { - c->prev = (*Qptr)->prev; - c->next = (*Qptr); - (*Qptr)->prev->next = c; - (*Qptr)->prev = c; - } -} - -static inline CommandList_struct *removeQ(CommandList_struct **Qptr, - CommandList_struct *c) -{ - if (c && c->next != c) { - if (*Qptr == c) *Qptr = c->next; - c->prev->next = c->next; - c->next->prev = c->prev; - } else { - *Qptr = NULL; - } - return c; -} - /* * Takes jobs of the Q and sends them to the hardware, then puts it on * the Q to wait for completion. diff --git a/drivers/block/ida_ioctl.h b/drivers/block/ida_ioctl.h index e90825be7..4159e52e8 100644 --- a/drivers/block/ida_ioctl.h +++ b/drivers/block/ida_ioctl.h @@ -57,7 +57,7 @@ typedef struct { /* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */ struct { - void *addr; + void __user *addr; size_t size; } sg[SG_MAX]; int sg_cnt; diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c index 4f090dcc5..55d1c0a1f 100644 --- a/drivers/block/paride/epat.c +++ b/drivers/block/paride/epat.c @@ -31,6 +31,12 @@ #define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) #define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) +static int epatc8; + +module_param(epatc8, int, 0); +MODULE_PARM_DESC(epatc8, "support for the Shuttle EP1284 chip, " + "used in any recent Imation SuperDisk (LS-120) drive."); + /* cont = 0 IDE register file cont = 1 IDE control registers cont = 2 internal EPAT registers @@ -209,15 +215,18 @@ static void epat_connect ( PIA *pi ) { pi->saved_r0 = r0(); pi->saved_r2 = r2(); -#ifdef CONFIG_PARIDE_EPATC8 /* Initialize the chip */ - CPP(0);CPP(0x40);CPP(0xe0); - w0(0);w2(1);w2(4); - WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10); - WR(0xe,0xf);WR(0xf,4); - /* WR(0xe,0xa);WR(0xf,4); */ - WR(0xe,0xd);WR(0xf,0); - /* CPP(0x30); */ + CPP(0); + + if (epatc8) { + CPP(0x40);CPP(0xe0); + w0(0);w2(1);w2(4); + WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10); + WR(0xe,0xf);WR(0xf,4); + /* WR(0xe,0xa);WR(0xf,4); */ + WR(0xe,0xd);WR(0xf,0); + /* CPP(0x30); */ + } /* Connect to the chip */ CPP(0xe0); @@ -227,15 +236,10 @@ static void epat_connect ( PIA *pi ) /* Request EPP */ w0(0x40);w2(6);w2(7);w2(4);w2(0xc);w2(4); } -#else - CPP(0); CPP(0xe0); - w0(0); w2(1); w2(4); - if (pi->mode >= 3) { - w0(0); w2(1); w2(4); w2(0xc); - w0(0x40); w2(6); w2(7); w2(4); w2(0xc); w2(4); + + if (!epatc8) { + WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10); } - WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10); -#endif } static void epat_disconnect (PIA *pi) @@ -320,6 +324,9 @@ static struct pi_protocol epat = { static int __init epat_init(void) { +#ifdef CONFIG_PARIDE_EPATC8 + epatc8 = 1; +#endif return pi_register(&epat)-1; } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 1e430e5c8..b4a696e73 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -337,7 +337,7 @@ static int pf_open(struct inode *inode, struct file *file) static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; - struct hd_geometry *geo = (struct hd_geometry *) arg; + struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; struct hd_geometry g; sector_t capacity; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index b4ae8414c..1fd72e005 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -330,12 +330,12 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) case HDIO_GETGEO: { struct hd_geometry g; - struct hd_geometry *geometry = (struct hd_geometry *) arg; + struct hd_geometry __user *geom= (void __user *)arg; g.heads = p->heads; g.sectors = p->sectors; g.cylinders = p->cylinders; g.start = get_start_sect(inode->i_bdev); - return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; + return copy_to_user(geom, &g, sizeof(g)) ? -EFAULT : 0; } case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -354,9 +354,9 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) } return 0; case HDIO_GET_DMA: - return put_user(!nodma, (long *) arg); + return put_user(!nodma, (long __user *) arg); case HDIO_GET_MULTCOUNT: - return put_user(xd_maxsectors, (long *) arg); + return put_user(xd_maxsectors, (long __user *) arg); default: return -EINVAL; } diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 871f38329..9faa8a08a 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -127,7 +127,7 @@ static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait) } /* Get packet from user space buffer(already verified) */ -static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char *buf, size_t count) +static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char __user *buf, size_t count) { struct sk_buff *skb; @@ -152,7 +152,7 @@ static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const } /* Write */ -static ssize_t hci_vhci_chr_write(struct file * file, const char * buf, +static ssize_t hci_vhci_chr_write(struct file * file, const char __user * buf, size_t count, loff_t *pos) { struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; @@ -165,10 +165,11 @@ static ssize_t hci_vhci_chr_write(struct file * file, const char * buf, /* Put packet to user space buffer(already verified) */ static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci, - struct sk_buff *skb, char *buf, int count) + struct sk_buff *skb, char __user *buf, + int count) { int len = count, total = 0; - char *ptr = buf; + char __user *ptr = buf; len = min_t(unsigned int, skb->len, len); if (copy_to_user(ptr, skb->data, len)) @@ -194,7 +195,7 @@ static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci, } /* Read */ -static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, loff_t *pos) +static ssize_t hci_vhci_chr_read(struct file * file, char __user * buf, size_t count, loff_t *pos) { struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; DECLARE_WAITQUEUE(wait, current); diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 4b3834923..3a758a020 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -2595,11 +2595,10 @@ static int read_audio(struct cdrom_read_audio *ra) retval = -EIO; goto exit_read_audio; } - } else if (copy_to_user((char *)(ra->buf + + } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW - * cframe)), - (char *) - readahead_buffer, + * cframe), + readahead_buffer, CD_FRAMESIZE_RAW)) { retval = -EFAULT; goto exit_read_audio; @@ -2612,8 +2611,7 @@ static int read_audio(struct cdrom_read_audio *ra) retval = -EIO; goto exit_read_audio; } - } else if (copy_to_user((char *)(ra->buf + (CD_FRAMESIZE_RAW * - cframe)), + } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), (char *)readahead_buffer, CD_FRAMESIZE_RAW)) { retval = -EFAULT; @@ -2945,6 +2943,7 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi, static int scd_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; int i; switch (cmd) { @@ -2959,7 +2958,7 @@ static int scd_dev_ioctl(struct cdrom_device_info *cdi, return -EIO; } - if (copy_from_user(&ra, (char *) arg, sizeof(ra))) + if (copy_from_user(&ra, argp, sizeof(ra))) return -EFAULT; if (ra.nframes == 0) { diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 7e9758fe7..62e2d11b3 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -1440,12 +1440,12 @@ static int cdromresume(void) } -static int cdromplaymsf(unsigned long arg) +static int cdromplaymsf(void __user *arg) { int status; struct cdrom_msf msf; - if (copy_from_user(&msf, (void *) arg, sizeof msf)) + if (copy_from_user(&msf, arg, sizeof msf)) return -EFAULT; bin2bcd(&msf); @@ -1461,13 +1461,13 @@ static int cdromplaymsf(unsigned long arg) } -static int cdromplaytrkind(unsigned long arg) +static int cdromplaytrkind(void __user *arg) { int status; struct cdrom_ti ti; struct cdrom_msf msf; - if (copy_from_user(&ti, (void *) arg, sizeof ti)) + if (copy_from_user(&ti, arg, sizeof ti)) return -EFAULT; if (ti.cdti_trk0 < disk_info.first @@ -1505,23 +1505,23 @@ static int cdromplaytrkind(unsigned long arg) } -static int cdromreadtochdr(unsigned long arg) +static int cdromreadtochdr(void __user *arg) { struct cdrom_tochdr tochdr; tochdr.cdth_trk0 = disk_info.first; tochdr.cdth_trk1 = disk_info.last; - return copy_to_user((void *)arg, &tochdr, sizeof tochdr) ? -EFAULT : 0; + return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0; } -static int cdromreadtocentry(unsigned long arg) +static int cdromreadtocentry(void __user *arg) { struct cdrom_tocentry entry; struct cdrom_subchnl *tocptr; - if (copy_from_user(&entry, (void *) arg, sizeof entry)) + if (copy_from_user(&entry, arg, sizeof entry)) return -EFAULT; if (entry.cdte_track == CDROM_LEADOUT) @@ -1544,17 +1544,17 @@ static int cdromreadtocentry(unsigned long arg) else if (entry.cdte_format != CDROM_MSF) return -EINVAL; - return copy_to_user((void *)arg, &entry, sizeof entry) ? -EFAULT : 0; + return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0; } -static int cdromvolctrl(unsigned long arg) +static int cdromvolctrl(void __user *arg) { int status; struct cdrom_volctrl volctrl; struct cdrom_msf msf; - if (copy_from_user(&volctrl, (char *) arg, sizeof volctrl)) + if (copy_from_user(&volctrl, arg, sizeof volctrl)) return -EFAULT; msf.cdmsf_min0 = 0x10; @@ -1573,12 +1573,12 @@ static int cdromvolctrl(unsigned long arg) } -static int cdromsubchnl(unsigned long arg) +static int cdromsubchnl(void __user *arg) { int status; struct cdrom_subchnl subchnl; - if (copy_from_user(&subchnl, (void *) arg, sizeof subchnl)) + if (copy_from_user(&subchnl, arg, sizeof subchnl)) return -EFAULT; if (subchnl.cdsc_format != CDROM_LBA @@ -1591,7 +1591,7 @@ static int cdromsubchnl(unsigned long arg) return -EIO; } - if (copy_to_user((void *)arg, &subchnl, sizeof subchnl)) + if (copy_to_user(arg, &subchnl, sizeof subchnl)) return -EFAULT; return 0; } @@ -1600,12 +1600,12 @@ static int cdromsubchnl(unsigned long arg) static struct gendisk *optcd_disk; -static int cdromread(unsigned long arg, int blocksize, int cmd) +static int cdromread(void __user *arg, int blocksize, int cmd) { int status; struct cdrom_msf msf; - if (copy_from_user(&msf, (void *) arg, sizeof msf)) + if (copy_from_user(&msf, arg, sizeof msf)) return -EFAULT; bin2bcd(&msf); @@ -1621,19 +1621,19 @@ static int cdromread(unsigned long arg, int blocksize, int cmd) fetch_data(optcd_disk->private_data, blocksize); - if (copy_to_user((void *)arg, optcd_disk->private_data, blocksize)) + if (copy_to_user(arg, optcd_disk->private_data, blocksize)) return -EFAULT; return 0; } -static int cdromseek(unsigned long arg) +static int cdromseek(void __user *arg) { int status; struct cdrom_msf msf; - if (copy_from_user(&msf, (void *)arg, sizeof msf)) + if (copy_from_user(&msf, arg, sizeof msf)) return -EFAULT; bin2bcd(&msf); @@ -1648,11 +1648,11 @@ static int cdromseek(unsigned long arg) #ifdef MULTISESSION -static int cdrommultisession(unsigned long arg) +static int cdrommultisession(void __user *arg) { struct cdrom_multisession ms; - if (copy_from_user(&ms, (void*) arg, sizeof ms)) + if (copy_from_user(&ms, arg, sizeof ms)) return -EFAULT; ms.addr.msf.minute = disk_info.last_session.minute; @@ -1667,7 +1667,7 @@ static int cdrommultisession(unsigned long arg) ms.xa_flag = disk_info.xa; - if (copy_to_user((void *)arg, &ms, sizeof(struct cdrom_multisession))) + if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession))) return -EFAULT; #if DEBUG_MULTIS @@ -1717,6 +1717,7 @@ static int opt_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { int status, err, retval = 0; + void __user *argp = (void __user *)arg; DEBUG((DEBUG_VFS, "starting opt_ioctl")); @@ -1767,10 +1768,10 @@ static int opt_ioctl(struct inode *ip, struct file *fp, switch (cmd) { case CDROMPAUSE: retval = cdrompause(); break; case CDROMRESUME: retval = cdromresume(); break; - case CDROMPLAYMSF: retval = cdromplaymsf(arg); break; - case CDROMPLAYTRKIND: retval = cdromplaytrkind(arg); break; - case CDROMREADTOCHDR: retval = cdromreadtochdr(arg); break; - case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break; + case CDROMPLAYMSF: retval = cdromplaymsf(argp); break; + case CDROMPLAYTRKIND: retval = cdromplaytrkind(argp); break; + case CDROMREADTOCHDR: retval = cdromreadtochdr(argp); break; + case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break; case CDROMSTOP: err = exec_cmd(COMSTOP); if (err < 0) { @@ -1799,8 +1800,8 @@ static int opt_ioctl(struct inode *ip, struct file *fp, } break; - case CDROMVOLCTRL: retval = cdromvolctrl(arg); break; - case CDROMSUBCHNL: retval = cdromsubchnl(arg); break; + case CDROMVOLCTRL: retval = cdromvolctrl(argp); break; + case CDROMSUBCHNL: retval = cdromsubchnl(argp); break; /* The drive detects the mode and automatically delivers the correct 2048 bytes, so we don't need these IOCTLs */ @@ -1814,7 +1815,7 @@ static int opt_ioctl(struct inode *ip, struct file *fp, break; #ifdef MULTISESSION - case CDROMMULTISESSION: retval = cdrommultisession(arg); break; + case CDROMMULTISESSION: retval = cdrommultisession(argp); break; #endif case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */ @@ -1822,16 +1823,16 @@ static int opt_ioctl(struct inode *ip, struct file *fp, case CDROMREADRAW: /* this drive delivers 2340 bytes in raw mode */ - retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW); + retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW); break; case CDROMREADCOOKED: - retval = cdromread(arg, CD_FRAMESIZE, COMREAD); + retval = cdromread(argp, CD_FRAMESIZE, COMREAD); break; case CDROMREADALL: - retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL); + retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL); break; - case CDROMSEEK: retval = cdromseek(arg); break; + case CDROMSEEK: retval = cdromseek(argp); break; case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */ case CDROMCLOSETRAY: break; /* The action was taken earlier */ default: retval = -EINVAL; diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 810887818..0e60b5c6a 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -716,13 +716,11 @@ static int sjcd_tray_open(void) static int sjcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; #if defined( SJCD_TRACE ) printk("SJCD:ioctl\n"); #endif - if (ip == NULL) - return (-EINVAL); - sjcd_get_status(); if (!sjcd_status_valid) return (-EIO); @@ -795,7 +793,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, #if defined( SJCD_TRACE ) printk("SJCD: ioctl: playtrkind\n"); #endif - if (!copy_from_user(&ti, (void *) arg, sizeof(ti))) { + if (!copy_from_user(&ti, argp, sizeof(ti))) { s = 0; if (ti.cdti_trk0 < sjcd_first_track_no) return (-EINVAL); @@ -833,7 +831,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, printk("SJCD: ioctl: playmsf\n"); #endif if ((s = - verify_area(VERIFY_READ, (void *) arg, + verify_area(VERIFY_READ, argp, sizeof(sjcd_msf))) == 0) { if (sjcd_audio_status == CDROM_AUDIO_PLAY) { sjcd_send_cmd(SCMD_PAUSE); @@ -842,7 +840,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, CDROM_AUDIO_NO_STATUS; } - if (copy_from_user(&sjcd_msf, (void *) arg, + if (copy_from_user(&sjcd_msf, argp, sizeof(sjcd_msf))) return (-EFAULT); @@ -877,7 +875,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, #endif toc_header.cdth_trk0 = sjcd_first_track_no; toc_header.cdth_trk1 = sjcd_last_track_no; - if (copy_to_user((void *)arg, &toc_header, + if (copy_to_user(argp, &toc_header, sizeof(toc_header))) return -EFAULT; return 0; @@ -890,11 +888,11 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, printk("SJCD: ioctl: readtocentry\n"); #endif if ((s = - verify_area(VERIFY_WRITE, (void *) arg, + verify_area(VERIFY_WRITE, argp, sizeof(toc_entry))) == 0) { struct sjcd_hw_disk_info *tp; - if (copy_from_user(&toc_entry, (void *) arg, + if (copy_from_user(&toc_entry, argp, sizeof(toc_entry))) return (-EFAULT); if (toc_entry.cdte_track == CDROM_LEADOUT) @@ -931,7 +929,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, default: return (-EINVAL); } - if (copy_to_user((void *) arg, &toc_entry, + if (copy_to_user(argp, &toc_entry, sizeof(toc_entry))) s = -EFAULT; } @@ -945,11 +943,11 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, printk("SJCD: ioctl: subchnl\n"); #endif if ((s = - verify_area(VERIFY_WRITE, (void *) arg, + verify_area(VERIFY_WRITE, argp, sizeof(subchnl))) == 0) { struct sjcd_hw_qinfo q_info; - if (copy_from_user(&subchnl, (void *) arg, + if (copy_from_user(&subchnl, argp, sizeof(subchnl))) return (-EFAULT); @@ -990,7 +988,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, default: return (-EINVAL); } - if (copy_to_user((void *) arg, &subchnl, + if (copy_to_user(argp, &subchnl, sizeof(subchnl))) s = -EFAULT; } @@ -1004,11 +1002,11 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, printk("SJCD: ioctl: volctrl\n"); #endif if ((s = - verify_area(VERIFY_READ, (void *) arg, + verify_area(VERIFY_READ, argp, sizeof(vol_ctrl))) == 0) { unsigned char dummy[4]; - if (copy_from_user(&vol_ctrl, (void *) arg, + if (copy_from_user(&vol_ctrl, argp, sizeof(vol_ctrl))) return (-EFAULT); sjcd_send_4_cmd(SCMD_SET_VOLUME, @@ -1038,8 +1036,7 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp, #if defined( SJCD_TRACE ) printk("SJCD: ioctl: statistic\n"); #endif - if (copy_to_user((void *)arg, &statistic, - sizeof(statistic))) + if (copy_to_user(argp, &statistic, sizeof(statistic))) return -EFAULT; return 0; } diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index 1d55bf861..a0c9c8d42 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -997,7 +997,7 @@ read_subcode(void) * (not BCD), so all the conversions are done. */ static int -sony_get_subchnl_info(long arg) +sony_get_subchnl_info(void __user *arg) { struct cdrom_subchnl schi; @@ -1009,7 +1009,7 @@ sony_get_subchnl_info(long arg) if (!sony_toc_read) { return -EIO; } - if (copy_from_user(&schi, (char *)arg, sizeof schi)) + if (copy_from_user(&schi, arg, sizeof schi)) return -EFAULT; switch (sony_audio_status) { @@ -1025,7 +1025,7 @@ sony_get_subchnl_info(long arg) case CDROM_AUDIO_NO_STATUS: schi.cdsc_audiostatus = sony_audio_status; - if (copy_to_user((char *)arg, &schi, sizeof schi)) + if (copy_to_user(arg, &schi, sizeof schi)) return -EFAULT; return 0; break; @@ -1053,7 +1053,7 @@ sony_get_subchnl_info(long arg) schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); } - return copy_to_user((char *)arg, &schi, sizeof schi) ? -EFAULT : 0; + return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; } @@ -1070,6 +1070,7 @@ cdu_ioctl(struct inode *inode, Byte cmd_buff[10], params[10]; int i; int dsc_status; + void __user *argp = (void __user *)arg; if (check_drive_status() != 0) return -EIO; @@ -1152,7 +1153,7 @@ cdu_ioctl(struct inode *inode, break; case CDROMPLAYMSF: /* Play starting at the given MSF address. */ - if (copy_from_user(params, (void *)arg, 6)) + if (copy_from_user(params, argp, 6)) return -EFAULT; spin_up_drive(status); set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); @@ -1184,13 +1185,12 @@ cdu_ioctl(struct inode *inode, case CDROMREADTOCHDR: /* Read the table of contents header */ { - struct cdrom_tochdr *hdr; + struct cdrom_tochdr __user *hdr = argp; struct cdrom_tochdr loc_hdr; sony_get_toc(); if (!sony_toc_read) return -EIO; - hdr = (struct cdrom_tochdr *)arg; loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) @@ -1201,7 +1201,7 @@ cdu_ioctl(struct inode *inode, case CDROMREADTOCENTRY: /* Read a given table of contents entry */ { - struct cdrom_tocentry *entry; + struct cdrom_tocentry __user *entry = argp; struct cdrom_tocentry loc_entry; int track_idx; Byte *msf_val = NULL; @@ -1210,7 +1210,6 @@ cdu_ioctl(struct inode *inode, if (!sony_toc_read) { return -EIO; } - entry = (struct cdrom_tocentry *)arg; if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) return -EFAULT; @@ -1252,7 +1251,7 @@ cdu_ioctl(struct inode *inode, if (!sony_toc_read) return -EIO; - if (copy_from_user(&ti, (char *)arg, sizeof ti)) + if (copy_from_user(&ti, argp, sizeof ti)) return -EFAULT; if ((ti.cdti_trk0 < sony_toc->first_track_num) || (sony_toc->last_track_num < ti.cdti_trk0) @@ -1314,14 +1313,13 @@ cdu_ioctl(struct inode *inode, } case CDROMSUBCHNL: /* Get subchannel info */ - return sony_get_subchnl_info(arg); + return sony_get_subchnl_info(argp); case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ { struct cdrom_volctrl volctrl; - if (copy_from_user(&volctrl, (char *)arg, - sizeof volctrl)) + if (copy_from_user(&volctrl, argp, sizeof volctrl)) return -EFAULT; cmd_buff[0] = SONY535_SET_VOLUME; cmd_buff[1] = volctrl.channel0; diff --git a/drivers/char/drm/drm_irq.h b/drivers/char/drm/drm_irq.h new file mode 100644 index 000000000..1d1d95116 --- /dev/null +++ b/drivers/char/drm/drm_irq.h @@ -0,0 +1,371 @@ +/** + * \file drm_irq.h + * IRQ support + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" + +#include /* For task queue support */ + +#ifndef __HAVE_SHARED_IRQ +#define __HAVE_SHARED_IRQ 0 +#endif + +#if __HAVE_SHARED_IRQ +#define DRM_IRQ_TYPE SA_SHIRQ +#else +#define DRM_IRQ_TYPE 0 +#endif + +/** + * Get interrupt from bus id. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_irq_busid structure. + * \return zero on success or a negative number on failure. + * + * Finds the PCI device with the specified bus id and gets its IRQ number. + * This IOCTL is deprecated, and will now return EINVAL for any busid not equal + * to that of the device that this DRM instance attached to. + */ +int DRM(irq_by_busid)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_irq_busid_t p; + + if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) + return -EFAULT; + + if ((p.busnum >> 8) != dev->pci_domain || + (p.busnum & 0xff) != dev->pci_bus || + p.devnum != dev->pci_slot || + p.funcnum != dev->pci_func) + return -EINVAL; + + p.irq = dev->irq; + + DRM_DEBUG("%d:%d:%d => IRQ %d\n", + p.busnum, p.devnum, p.funcnum, p.irq); + if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p))) + return -EFAULT; + return 0; +} + +#if __HAVE_IRQ + +/** + * Install IRQ handler. + * + * \param dev DRM device. + * \param irq IRQ number. + * + * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver + * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions + * before and after the installation. + */ +int DRM(irq_install)( drm_device_t *dev ) +{ + int ret; + + if ( dev->irq == 0 ) + return -EINVAL; + + down( &dev->struct_sem ); + + /* Driver must have been initialized */ + if ( !dev->dev_private ) { + up( &dev->struct_sem ); + return -EINVAL; + } + + if ( dev->irq_enabled ) { + up( &dev->struct_sem ); + return -EBUSY; + } + dev->irq_enabled = 1; + up( &dev->struct_sem ); + + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); + +#if __HAVE_DMA + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; +#endif + +#if __HAVE_IRQ_BH + INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev); +#endif + +#if __HAVE_VBL_IRQ + init_waitqueue_head(&dev->vbl_queue); + + spin_lock_init( &dev->vbl_lock ); + + INIT_LIST_HEAD( &dev->vbl_sigs.head ); + + dev->vbl_pending = 0; +#endif + + /* Before installing handler */ + DRM(driver_irq_preinstall)(dev); + + /* Install handler */ + ret = request_irq( dev->irq, DRM(irq_handler), + DRM_IRQ_TYPE, dev->devname, dev ); + if ( ret < 0 ) { + down( &dev->struct_sem ); + dev->irq_enabled = 0; + up( &dev->struct_sem ); + return ret; + } + + /* After installing handler */ + DRM(driver_irq_postinstall)(dev); + + return 0; +} + +/** + * Uninstall the IRQ handler. + * + * \param dev DRM device. + * + * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. + */ +int DRM(irq_uninstall)( drm_device_t *dev ) +{ + int irq_enabled; + + down( &dev->struct_sem ); + irq_enabled = dev->irq_enabled; + dev->irq_enabled = 0; + up( &dev->struct_sem ); + + if ( !irq_enabled ) + return -EINVAL; + + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); + + DRM(driver_irq_uninstall)( dev ); + + free_irq( dev->irq, dev ); + + return 0; +} + +/** + * IRQ control ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_control structure. + * \return zero on success or a negative number on failure. + * + * Calls irq_install() or irq_uninstall() according to \p arg. + */ +int DRM(control)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_control_t ctl; + + if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) + return -EFAULT; + + switch ( ctl.func ) { + case DRM_INST_HANDLER: + if (dev->if_version < DRM_IF_VERSION(1, 2) && + ctl.irq != dev->irq) + return -EINVAL; + return DRM(irq_install)( dev ); + case DRM_UNINST_HANDLER: + return DRM(irq_uninstall)( dev ); + default: + return -EINVAL; + } +} + +#if __HAVE_VBL_IRQ + +/** + * Wait for VBLANK. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param data user argument, pointing to a drm_wait_vblank structure. + * \return zero on success or a negative number on failure. + * + * Verifies the IRQ is installed. + * + * If a signal is requested checks if this task has already scheduled the same signal + * for the same vblank sequence number - nothing to be done in + * that case. If the number of tasks waiting for the interrupt exceeds 100 the + * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this + * task. + * + * If a signal is not requested, then calls vblank_wait(). + */ +int DRM(wait_vblank)( DRM_IOCTL_ARGS ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_wait_vblank_t vblwait; + struct timeval now; + int ret = 0; + unsigned int flags; + + if (!dev->irq) + return -EINVAL; + + DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, + sizeof(vblwait) ); + + switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { + case _DRM_VBLANK_RELATIVE: + vblwait.request.sequence += atomic_read( &dev->vbl_received ); + vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; + case _DRM_VBLANK_ABSOLUTE: + break; + default: + return -EINVAL; + } + + flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + + if ( flags & _DRM_VBLANK_SIGNAL ) { + unsigned long irqflags; + drm_vbl_sig_t *vbl_sig; + + vblwait.reply.sequence = atomic_read( &dev->vbl_received ); + + spin_lock_irqsave( &dev->vbl_lock, irqflags ); + + /* Check if this task has already scheduled the same signal + * for the same vblank sequence number; nothing to be done in + * that case + */ + list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { + if (vbl_sig->sequence == vblwait.request.sequence + && vbl_sig->info.si_signo == vblwait.request.signal + && vbl_sig->task == current) + { + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + goto done; + } + } + + if ( dev->vbl_pending >= 100 ) { + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + return -EBUSY; + } + + dev->vbl_pending++; + + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + + if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { + return -ENOMEM; + } + + memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); + + vbl_sig->sequence = vblwait.request.sequence; + vbl_sig->info.si_signo = vblwait.request.signal; + vbl_sig->task = current; + + spin_lock_irqsave( &dev->vbl_lock, irqflags ); + + list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head ); + + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + } else { + ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); + + do_gettimeofday( &now ); + vblwait.reply.tval_sec = now.tv_sec; + vblwait.reply.tval_usec = now.tv_usec; + } + +done: + DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, + sizeof(vblwait) ); + + return ret; +} + +/** + * Send the VBLANK signals. + * + * \param dev DRM device. + * + * Sends a signal for each task in drm_device::vbl_sigs and empties the list. + * + * If a signal is not requested, then calls vblank_wait(). + */ +void DRM(vbl_send_signals)( drm_device_t *dev ) +{ + struct list_head *list, *tmp; + drm_vbl_sig_t *vbl_sig; + unsigned int vbl_seq = atomic_read( &dev->vbl_received ); + unsigned long flags; + + spin_lock_irqsave( &dev->vbl_lock, flags ); + + list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { + vbl_sig = list_entry( list, drm_vbl_sig_t, head ); + if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { + vbl_sig->info.si_code = vbl_seq; + send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); + + list_del( list ); + + DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); + + dev->vbl_pending--; + } + } + + spin_unlock_irqrestore( &dev->vbl_lock, flags ); +} + +#endif /* __HAVE_VBL_IRQ */ + +#endif /* __HAVE_IRQ */ diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h new file mode 100644 index 000000000..3b5f8d3a2 --- /dev/null +++ b/drivers/char/drm/drm_pciids.h @@ -0,0 +1,203 @@ +/* + This file is auto-generated from the drm_pciids.txt in the DRM CVS + Please contact dri-devel@lists.sf.net to add new cards to this list +*/ +#define radeon_PCI_IDS \ + {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x514F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define r128_PCI_IDS \ + {0x1002, 0x4c45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4d46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5041, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5044, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5045, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5046, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5047, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5048, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5049, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x504F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x524b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x524c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x534d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x544C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x5452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define mga_PCI_IDS \ + {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define mach64_PCI_IDS \ + {0x1002, 0x4749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x474c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x474f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x474d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x474e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1002, 0x4c4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define sisdrv_PCI_IDS \ + {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define tdfx_PCI_IDS \ + {0x121a, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x121a, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x121a, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x121a, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x121a, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x121a, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define viadrv_PCI_IDS \ + {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define i810_PCI_IDS \ + {0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x7125, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x1132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define i830_PCI_IDS \ + {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define gamma_PCI_IDS \ + {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define savage_PCI_IDS \ + {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + +#define ffb_PCI_IDS \ + {0, 0, 0} + diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c index 3a3bf011a..83e2f6c04 100644 --- a/drivers/char/drm/radeon_mem.c +++ b/drivers/char/drm/radeon_mem.c @@ -137,12 +137,12 @@ static int init_heap(struct mem_block **heap, int start, int size) struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks)); if (!blocks) - return -ENOMEM; + return DRM_ERR(ENOMEM); *heap = DRM_MALLOC(sizeof(**heap)); if (!*heap) { DRM_FREE( blocks, sizeof(*blocks) ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } blocks->start = start; diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 577950510..ad4a96704 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -79,7 +79,7 @@ MODULE_PARM_DESC(force, "Force loading without checking for supported models"); MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static ssize_t i8k_read(struct file *, char *, size_t, loff_t *); +static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *); static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -330,10 +330,10 @@ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, int val; int speed; unsigned char buff[16]; + int __user *argp = (int __user *)arg; - if (!arg) { + if (!argp) return -EINVAL; - } switch (cmd) { case I8K_BIOS_VERSION: @@ -358,14 +358,14 @@ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, break; case I8K_GET_SPEED: - if (copy_from_user(&val, (int *)arg, sizeof(int))) { + if (copy_from_user(&val, argp, sizeof(int))) { return -EFAULT; } val = i8k_get_fan_speed(val); break; case I8K_GET_FAN: - if (copy_from_user(&val, (int *)arg, sizeof(int))) { + if (copy_from_user(&val, argp, sizeof(int))) { return -EFAULT; } val = i8k_get_fan_status(val); @@ -375,10 +375,10 @@ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, if (restricted && !capable(CAP_SYS_ADMIN)) { return -EPERM; } - if (copy_from_user(&val, (int *)arg, sizeof(int))) { + if (copy_from_user(&val, argp, sizeof(int))) { return -EFAULT; } - if (copy_from_user(&speed, (int *)arg+1, sizeof(int))) { + if (copy_from_user(&speed, argp+1, sizeof(int))) { return -EFAULT; } val = i8k_set_fan(val, speed); @@ -394,17 +394,17 @@ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, switch (cmd) { case I8K_BIOS_VERSION: - if (copy_to_user((int *)arg, &val, 4)) { + if (copy_to_user(argp, &val, 4)) { return -EFAULT; } break; case I8K_MACHINE_ID: - if (copy_to_user((int *)arg, buff, 16)) { + if (copy_to_user(argp, buff, 16)) { return -EFAULT; } break; default: - if (copy_to_user((int *)arg, &val, sizeof(int))) { + if (copy_to_user(argp, &val, sizeof(int))) { return -EFAULT; } break; @@ -462,7 +462,7 @@ static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) return n; } -static ssize_t i8k_read(struct file *f, char *buffer, size_t len, loff_t *fpos) +static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos) { int n; char info[128]; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c1e4abf14..aa0fe2dbf 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -123,6 +123,12 @@ struct ipmi_channel unsigned char protocol; }; +struct ipmi_proc_entry +{ + char *name; + struct ipmi_proc_entry *next; +}; + #define IPMI_IPMB_NUM_SEQ 64 #define IPMI_MAX_CHANNELS 8 struct ipmi_smi @@ -149,6 +155,11 @@ struct ipmi_smi struct ipmi_smi_handlers *handlers; void *send_info; + /* A list of proc entries for this interface. This does not + need a lock, only one thread creates it and only one thread + destroys it. */ + struct ipmi_proc_entry *proc_entries; + /* A table of sequence numbers for this interface. We use the sequence numbers for IPMB messages that go out of the interface to match them up with their responses. A routine @@ -1515,18 +1526,36 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, read_proc_t *read_proc, write_proc_t *write_proc, void *data, struct module *owner) { - struct proc_dir_entry *file; - int rv = 0; + struct proc_dir_entry *file; + int rv = 0; + struct ipmi_proc_entry *entry; + + /* Create a list element. */ + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->name = kmalloc(strlen(name)+1, GFP_KERNEL); + if (!entry->name) { + kfree(entry); + return -ENOMEM; + } + strcpy(entry->name, name); file = create_proc_entry(name, 0, smi->proc_dir); - if (!file) + if (!file) { + kfree(entry->name); + kfree(entry); rv = -ENOMEM; - else { + } else { file->nlink = 1; file->data = data; file->read_proc = read_proc; file->write_proc = write_proc; file->owner = owner; + + /* Stick it on the list. */ + entry->next = smi->proc_entries; + smi->proc_entries = entry; } return rv; @@ -1562,6 +1591,21 @@ static int add_proc_entries(ipmi_smi_t smi, int num) return rv; } +static void remove_proc_entries(ipmi_smi_t smi) +{ + struct ipmi_proc_entry *entry; + + while (smi->proc_entries) { + entry = smi->proc_entries; + smi->proc_entries = entry->next; + + remove_proc_entry(entry->name, smi->proc_dir); + kfree(entry->name); + kfree(entry); + } + remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); +} + static int send_channel_info_cmd(ipmi_smi_t intf, int chan) { @@ -1749,8 +1793,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, if (rv) { if (new_intf->proc_dir) - remove_proc_entry(new_intf->proc_dir_name, - proc_ipmi_root); + remove_proc_entries(new_intf); kfree(new_intf); } @@ -1806,8 +1849,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf) { for (i=0; iproc_dir_name, - proc_ipmi_root); + remove_proc_entries(intf); spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = NULL; clean_up_interface_data(intf); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 34ceaeed6..8a1fd40d5 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -905,10 +905,10 @@ MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the" " has an interrupt. Otherwise, set it to zero or leave" " it blank."); - -#if defined(CONFIG_ACPI_INTERPETER) || defined(CONFIG_X86) || defined(CONFIG_PCI) #define IPMI_MEM_ADDR_SPACE 1 #define IPMI_IO_ADDR_SPACE 2 + +#if defined(CONFIG_ACPI_INTERPETER) || defined(CONFIG_X86) || defined(CONFIG_PCI) static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr) { int i; diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 7b6ee59ed..b5f32d65e 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -250,7 +250,7 @@ static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) } static ssize_t -nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) +nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; @@ -279,7 +279,7 @@ nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) } static ssize_t -nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +nvram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index fb87f872f..970e2331a 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.21 2004/03/08 15:29:23 paulkf Exp $ + * $Id: synclink_cs.c,v 4.22 2004/06/01 20:27:46 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -438,15 +438,15 @@ static void bh_status(MGSLPC_INFO *info); static int tiocmget(struct tty_struct *tty, struct file *file); static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); -static int get_stats(MGSLPC_INFO *info, struct mgsl_icount *user_icount); -static int get_params(MGSLPC_INFO *info, MGSL_PARAMS *user_params); -static int set_params(MGSLPC_INFO *info, MGSL_PARAMS *new_params); -static int get_txidle(MGSLPC_INFO *info, int*idle_mode); +static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); +static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); +static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params); +static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); static int set_txidle(MGSLPC_INFO *info, int idle_mode); static int set_txenable(MGSLPC_INFO *info, int enable); static int tx_abort(MGSLPC_INFO *info); static int set_rxenable(MGSLPC_INFO *info, int enable); -static int wait_events(MGSLPC_INFO *info, int *mask); +static int wait_events(MGSLPC_INFO *info, int __user *mask); #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) @@ -489,7 +489,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.21 $"; +static char *driver_version = "$Revision: 4.22 $"; static struct tty_driver *serial_driver; @@ -521,8 +521,10 @@ static dev_link_t *dev_list = NULL; * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */ -static void* mgslpc_get_text_ptr(void); -static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;} +static void* mgslpc_get_text_ptr(void) +{ + return mgslpc_get_text_ptr; +} static dev_link_t *mgslpc_attach(void) { @@ -1955,7 +1957,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty) /* get the current serial statistics */ -static int get_stats(MGSLPC_INFO * info, struct mgsl_icount *user_icount) +static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1968,7 +1970,7 @@ static int get_stats(MGSLPC_INFO * info, struct mgsl_icount *user_icount) /* get the current serial parameters */ -static int get_params(MGSLPC_INFO * info, MGSL_PARAMS *user_params) +static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1988,7 +1990,7 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS *user_params) * * Returns: 0 if success, otherwise error code */ -static int set_params(MGSLPC_INFO * info, MGSL_PARAMS *new_params) +static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params) { unsigned long flags; MGSL_PARAMS tmp_params; @@ -2014,7 +2016,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS *new_params) return 0; } -static int get_txidle(MGSLPC_INFO * info, int*idle_mode) +static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2037,7 +2039,7 @@ static int set_txidle(MGSLPC_INFO * info, int idle_mode) return 0; } -static int get_interface(MGSLPC_INFO * info, int*if_mode) +static int get_interface(MGSLPC_INFO * info, int __user *if_mode) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2136,7 +2138,7 @@ static int set_rxenable(MGSLPC_INFO * info, int enable) * of events triggerred, * otherwise error code */ -static int wait_events(MGSLPC_INFO * info, int * mask_ptr) +static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) { unsigned long flags; int s; @@ -2409,20 +2411,21 @@ int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) { int error; struct mgsl_icount cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ + struct serial_icounter_struct __user *p_cuser; /* user space */ + void __user *argp = (void __user *)arg; unsigned long flags; switch (cmd) { case MGSL_IOCGPARAMS: - return get_params(info,(MGSL_PARAMS *)arg); + return get_params(info, argp); case MGSL_IOCSPARAMS: - return set_params(info,(MGSL_PARAMS *)arg); + return set_params(info, argp); case MGSL_IOCGTXIDLE: - return get_txidle(info,(int*)arg); + return get_txidle(info, argp); case MGSL_IOCSTXIDLE: - return set_txidle(info,(int)arg); + return set_txidle(info, (int)arg); case MGSL_IOCGIF: - return get_interface(info,(int*)arg); + return get_interface(info, argp); case MGSL_IOCSIF: return set_interface(info,(int)arg); case MGSL_IOCTXENABLE: @@ -2432,16 +2435,16 @@ int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) case MGSL_IOCTXABORT: return tx_abort(info); case MGSL_IOCGSTATS: - return get_stats(info,(struct mgsl_icount*)arg); + return get_stats(info, argp); case MGSL_IOCWAITEVENT: - return wait_events(info,(int*)arg); + return wait_events(info, argp); case TIOCMIWAIT: return modem_input_wait(info,(int)arg); case TIOCGICOUNT: spin_lock_irqsave(&info->lock,flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock,flags); - p_cuser = (struct serial_icounter_struct *) arg; + p_cuser = argp; PUT_USER(error,cnow.cts, &p_cuser->cts); if (error) return error; PUT_USER(error,cnow.dsr, &p_cuser->dsr); @@ -3130,9 +3133,35 @@ static struct tty_operations mgslpc_ops = { .tiocmset = tiocmset, }; +static void synclink_cs_cleanup(void) +{ + int rc; + + printk("Unloading %s: version %s\n", driver_name, driver_version); + + while(mgslpc_device_list) + mgslpc_remove_device(mgslpc_device_list); + + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + put_tty_driver(serial_driver); + } + + pcmcia_unregister_driver(&mgslpc_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + mgslpc_release((u_long)dev_list); + mgslpc_detach(dev_list); + } +} + static int __init synclink_cs_init(void) { - int error; + int rc; if (break_on_load) { mgslpc_get_text_ptr(); @@ -3141,14 +3170,13 @@ static int __init synclink_cs_init(void) printk("%s %s\n", driver_name, driver_version); - serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); - if (!serial_driver) - return -ENOMEM; + if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) + return rc; - error = pcmcia_register_driver(&mgslpc_driver); - if (error) { - put_tty_driver(serial_driver); - return error; + serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); + if (!serial_driver) { + rc = -ENOMEM; + goto error; } /* Initialize the tty_driver structure */ @@ -3166,39 +3194,28 @@ static int __init synclink_cs_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &mgslpc_ops); - if (tty_register_driver(serial_driver) < 0) + if ((rc = tty_register_driver(serial_driver)) < 0) { printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); + put_tty_driver(serial_driver); + serial_driver = NULL; + goto error; + } printk("%s %s, tty major#%d\n", driver_name, driver_version, serial_driver->major); return 0; + +error: + synclink_cs_cleanup(); + return rc; } static void __exit synclink_cs_exit(void) { - int rc; - - printk("Unloading %s: version %s\n", driver_name, driver_version); - - while(mgslpc_device_list) - mgslpc_remove_device(mgslpc_device_list); - - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); - - pcmcia_unregister_driver(&mgslpc_driver); - - /* XXX: this really needs to move into generic code.. */ - while (dev_list != NULL) { - if (dev_list->state & DEV_CONFIG) - mgslpc_release((u_long)dev_list); - mgslpc_detach(dev_list); - } + synclink_cs_cleanup(); } module_init(synclink_cs_init); diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 3758fb1b1..e937346e1 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -26,7 +26,7 @@ static int major = 0; /* default to dynamic major */ MODULE_PARM(major, "i"); MODULE_PARM_DESC(major, "Major device number"); -static ssize_t scx200_gpio_write(struct file *file, const char *data, +static ssize_t scx200_gpio_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { unsigned m = iminor(file->f_dentry->d_inode); @@ -77,7 +77,7 @@ static ssize_t scx200_gpio_write(struct file *file, const char *data, return len; } -static ssize_t scx200_gpio_read(struct file *file, char *buf, +static ssize_t scx200_gpio_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { unsigned m = iminor(file->f_dentry->d_inode); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index a3780cdef..a906dfad2 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -461,8 +461,9 @@ static int sonypi_misc_open(struct inode * inode, struct file * file) { return 0; } -static ssize_t sonypi_misc_read(struct file * file, char * buf, - size_t count, loff_t *pos) { +static ssize_t sonypi_misc_read(struct file * file, char __user * buf, + size_t count, loff_t *pos) +{ DECLARE_WAITQUEUE(wait, current); ssize_t i = count; unsigned char c; @@ -504,6 +505,7 @@ static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) { static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { int ret = 0; + void __user *argp = (void __user *)arg; u8 val8; u16 val16; @@ -514,11 +516,11 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, ret = -EIO; break; } - if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) + if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCSBRT: - if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) { + if (copy_from_user(&val8, argp, sizeof(val8))) { ret = -EFAULT; break; } @@ -530,7 +532,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, ret = -EIO; break; } - if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) + if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT1REM: @@ -538,7 +540,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, ret = -EIO; break; } - if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) + if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT2CAP: @@ -546,7 +548,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, ret = -EIO; break; } - if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) + if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT2REM: @@ -554,7 +556,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, ret = -EIO; break; } - if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) + if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBATFLAGS: @@ -563,16 +565,16 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, break; } val8 &= 0x07; - if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) + if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCGBLUE: val8 = sonypi_device.bluetooth_power; - if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) + if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCSBLUE: - if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) { + if (copy_from_user(&val8, argp, sizeof(val8))) { ret = -EFAULT; break; } diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index deefd713a..89f04b737 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.21 2004/03/08 15:29:22 paulkf Exp $ + * $Id: synclink.c,v 4.24 2004/06/03 14:50:09 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -782,7 +782,6 @@ int mgsl_claim_resources(struct mgsl_struct *info); void mgsl_release_resources(struct mgsl_struct *info); void mgsl_add_device(struct mgsl_struct *info); struct mgsl_struct* mgsl_allocate_device(void); -int mgsl_enum_isa_devices(void); /* * DMA buffer manupulation functions. @@ -853,19 +852,22 @@ static int tiocmget(struct tty_struct *tty, struct file *file); static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount - *user_icount); -static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params); -static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params); -static int mgsl_get_txidle(struct mgsl_struct * info, int*idle_mode); + __user *user_icount); +static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params); +static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params); +static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode); static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode); static int mgsl_txenable(struct mgsl_struct * info, int enable); static int mgsl_txabort(struct mgsl_struct * info); static int mgsl_rxenable(struct mgsl_struct * info, int enable); -static int mgsl_wait_event(struct mgsl_struct * info, int * mask); +static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); static int mgsl_loopmode_send_done( struct mgsl_struct * info ); #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) +/* set non-zero on successful registration with PCI subsystem */ +static int pci_registered; + /* * Global linked list of SyncLink devices */ @@ -909,7 +911,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.21 $"; +static char *driver_version = "$Revision: 4.24 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -950,8 +952,10 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */ -void* mgsl_get_text_ptr(void); -void* mgsl_get_text_ptr() {return mgsl_get_text_ptr;} +void* mgsl_get_text_ptr(void) +{ + return mgsl_get_text_ptr; +} /* * tmp_buf is used as a temporary buffer by mgsl_write. We need to @@ -2521,7 +2525,7 @@ static void mgsl_unthrottle(struct tty_struct * tty) * * Return Value: 0 if success, otherwise error code */ -static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount *user_icount) +static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user *user_icount) { int err; @@ -2550,7 +2554,7 @@ static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount *user_ic * * Return Value: 0 if success, otherwise error code */ -static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params) +static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2580,7 +2584,7 @@ static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params) * * Return Value: 0 if success, otherwise error code */ -static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params) +static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params) { unsigned long flags; MGSL_PARAMS tmp_params; @@ -2616,7 +2620,7 @@ static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params) * * Return Value: 0 if success, otherwise error code */ -static int mgsl_get_txidle(struct mgsl_struct * info, int*idle_mode) +static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode) { int err; @@ -2763,7 +2767,7 @@ static int mgsl_rxenable(struct mgsl_struct * info, int enable) * of events triggerred, * otherwise error code */ -static int mgsl_wait_event(struct mgsl_struct * info, int * mask_ptr) +static int mgsl_wait_event(struct mgsl_struct * info, int __user * mask_ptr) { unsigned long flags; int s; @@ -3051,16 +3055,17 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long { int error; struct mgsl_icount cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ + void __user *argp = (void __user *)arg; + struct serial_icounter_struct __user *p_cuser; /* user space */ unsigned long flags; switch (cmd) { case MGSL_IOCGPARAMS: - return mgsl_get_params(info,(MGSL_PARAMS *)arg); + return mgsl_get_params(info, argp); case MGSL_IOCSPARAMS: - return mgsl_set_params(info,(MGSL_PARAMS *)arg); + return mgsl_set_params(info, argp); case MGSL_IOCGTXIDLE: - return mgsl_get_txidle(info,(int*)arg); + return mgsl_get_txidle(info, argp); case MGSL_IOCSTXIDLE: return mgsl_set_txidle(info,(int)arg); case MGSL_IOCTXENABLE: @@ -3070,9 +3075,9 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long case MGSL_IOCTXABORT: return mgsl_txabort(info); case MGSL_IOCGSTATS: - return mgsl_get_stats(info,(struct mgsl_icount*)arg); + return mgsl_get_stats(info, argp); case MGSL_IOCWAITEVENT: - return mgsl_wait_event(info,(int*)arg); + return mgsl_wait_event(info, argp); case MGSL_IOCLOOPTXDONE: return mgsl_loopmode_send_done(info); /* Wait for modem input (DCD,RI,DSR,CTS) change @@ -3091,7 +3096,7 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long spin_lock_irqsave(&info->irq_spinlock,flags); cnow = info->icount; spin_unlock_irqrestore(&info->irq_spinlock,flags); - p_cuser = (struct serial_icounter_struct *) arg; + p_cuser = argp; PUT_USER(error,cnow.cts, &p_cuser->cts); if (error) return error; PUT_USER(error,cnow.dsr, &p_cuser->dsr); @@ -4425,7 +4430,7 @@ void mgsl_add_device( struct mgsl_struct *info ) * Arguments: none * Return Value: pointer to mgsl_struct if success, otherwise NULL */ -struct mgsl_struct* mgsl_allocate_device() +struct mgsl_struct* mgsl_allocate_device(void) { struct mgsl_struct *info; @@ -4484,10 +4489,11 @@ static struct tty_operations mgsl_ops = { /* * perform tty device initialization */ -int mgsl_init_tty(void); -int mgsl_init_tty() +static int mgsl_init_tty(void) { - serial_driver = alloc_tty_driver(mgsl_device_count); + int rc; + + serial_driver = alloc_tty_driver(128); if (!serial_driver) return -ENOMEM; @@ -4503,9 +4509,13 @@ int mgsl_init_tty() B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &mgsl_ops); - if (tty_register_driver(serial_driver) < 0) + if ((rc = tty_register_driver(serial_driver)) < 0) { printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); + put_tty_driver(serial_driver); + serial_driver = NULL; + return rc; + } printk("%s %s, tty major#%d\n", driver_name, driver_version, @@ -4515,7 +4525,7 @@ int mgsl_init_tty() /* enumerate user specified ISA adapters */ -int mgsl_enum_isa_devices() +static void mgsl_enum_isa_devices(void) { struct mgsl_struct *info; int i; @@ -4546,51 +4556,9 @@ int mgsl_enum_isa_devices() mgsl_add_device( info ); } - - return 0; } -/* mgsl_init() - * - * Driver initialization entry point. - * - * Arguments: None - * Return Value: 0 if success, otherwise error code - */ -int __init mgsl_init(void) -{ - int rc; - - printk("%s %s\n", driver_name, driver_version); - - mgsl_enum_isa_devices(); - pci_register_driver(&synclink_pci_driver); - - if ( !mgsl_device_list ) { - printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__); - return -ENODEV; - } - if ((rc = mgsl_init_tty())) - return rc; - - return 0; -} - -static int __init synclink_init(void) -{ -/* Uncomment this to kernel debug module. - * mgsl_get_text_ptr() leaves the .text address in eax - * which can be used with add-symbol-file with gdb. - */ - if (break_on_load) { - mgsl_get_text_ptr(); - BREAKPOINT(); - } - - return mgsl_init(); -} - -static void __exit synclink_exit(void) +static void synclink_cleanup(void) { int rc; struct mgsl_struct *info; @@ -4598,11 +4566,13 @@ static void __exit synclink_exit(void) printk("Unloading %s: %s\n", driver_name, driver_version); - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + put_tty_driver(serial_driver); + } - put_tty_driver(serial_driver); info = mgsl_device_list; while(info) { #ifdef CONFIG_SYNCLINK_SYNCPPP @@ -4620,7 +4590,40 @@ static void __exit synclink_exit(void) tmp_buf = NULL; } - pci_unregister_driver(&synclink_pci_driver); + if (pci_registered) + pci_unregister_driver(&synclink_pci_driver); +} + +static int __init synclink_init(void) +{ + int rc; + + if (break_on_load) { + mgsl_get_text_ptr(); + BREAKPOINT(); + } + + printk("%s %s\n", driver_name, driver_version); + + mgsl_enum_isa_devices(); + if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) + printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); + else + pci_registered = 1; + + if ((rc = mgsl_init_tty()) < 0) + goto error; + + return 0; + +error: + synclink_cleanup(); + return rc; +} + +static void __exit synclink_exit(void) +{ + synclink_cleanup(); } module_init(synclink_init); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index d82335ed7..e76454311 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.19 2004/03/08 15:29:23 paulkf Exp $ + * $Id: synclinkmp.c,v 4.22 2004/06/03 14:50:10 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -494,7 +494,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.19 $"; +static char *driver_version = "$Revision: 4.22 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -3781,56 +3781,7 @@ static struct tty_operations ops = { .tiocmset = tiocmset, }; -/* Driver initialization entry point. - */ - -static int __init synclinkmp_init(void) -{ - if (break_on_load) { - synclinkmp_get_text_ptr(); - BREAKPOINT(); - } - - printk("%s %s\n", driver_name, driver_version); - - synclinkmp_adapter_count = -1; - pci_register_driver(&synclinkmp_pci_driver); - - if ( !synclinkmp_device_list ) { - printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__); - return -ENODEV; - } - - serial_driver = alloc_tty_driver(synclinkmp_device_count); - if (!serial_driver) - return -ENOMEM; - - /* Initialize the tty_driver structure */ - - serial_driver->owner = THIS_MODULE; - serial_driver->driver_name = "synclinkmp"; - serial_driver->name = "ttySLM"; - serial_driver->major = ttymajor; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &ops); - if (tty_register_driver(serial_driver) < 0) - printk("%s(%d):Couldn't register serial driver\n", - __FILE__,__LINE__); - - printk("%s %s, tty major#%d\n", - driver_name, driver_version, - serial_driver->major); - - return 0; -} - -static void __exit synclinkmp_exit(void) +static void synclinkmp_cleanup(void) { unsigned long flags; int rc; @@ -3839,10 +3790,12 @@ static void __exit synclinkmp_exit(void) printk("Unloading %s %s\n", driver_name, driver_version); - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + put_tty_driver(serial_driver); + } info = synclinkmp_device_list; while(info) { @@ -3882,6 +3835,69 @@ static void __exit synclinkmp_exit(void) pci_unregister_driver(&synclinkmp_pci_driver); } +/* Driver initialization entry point. + */ + +static int __init synclinkmp_init(void) +{ + int rc; + + if (break_on_load) { + synclinkmp_get_text_ptr(); + BREAKPOINT(); + } + + printk("%s %s\n", driver_name, driver_version); + + if ((rc = pci_register_driver(&synclinkmp_pci_driver)) < 0) { + printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); + return rc; + } + + serial_driver = alloc_tty_driver(128); + if (!serial_driver) { + rc = -ENOMEM; + goto error; + } + + /* Initialize the tty_driver structure */ + + serial_driver->owner = THIS_MODULE; + serial_driver->driver_name = "synclinkmp"; + serial_driver->name = "ttySLM"; + serial_driver->major = ttymajor; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &ops); + if ((rc = tty_register_driver(serial_driver)) < 0) { + printk("%s(%d):Couldn't register serial driver\n", + __FILE__,__LINE__); + put_tty_driver(serial_driver); + serial_driver = NULL; + goto error; + } + + printk("%s %s, tty major#%d\n", + driver_name, driver_version, + serial_driver->major); + + return 0; + +error: + synclinkmp_cleanup(); + return rc; +} + +static void __exit synclinkmp_exit(void) +{ + synclinkmp_cleanup(); +} + module_init(synclinkmp_init); module_exit(synclinkmp_exit); diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 15e2c72ed..5b84af027 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -251,13 +251,14 @@ static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { SMMRegisters regs; + SMMRegisters __user *argp = (SMMRegisters __user *)arg; unsigned short ax,bx; int err; - if (!arg) + if (!argp) return -EINVAL; - if (copy_from_user(®s, (SMMRegisters *) arg, sizeof(SMMRegisters))) + if (copy_from_user(®s, argp, sizeof(SMMRegisters))) return -EFAULT; switch (cmd) { @@ -281,7 +282,7 @@ static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, return -EINVAL; } - if (copy_to_user((SMMRegisters *) arg, ®s, sizeof(SMMRegisters))) + if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) return -EFAULT; return (err==0) ? 0:-EINVAL; diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 698c2c451..6ee95af21 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -1727,7 +1727,7 @@ static irqreturn_t qic02_tape_interrupt(int irq, void *dev_id, * request would return the EOF flag for the previous file. */ -static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, loff_t * ppos) +static ssize_t qic02_tape_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) { int type = iminor(filp->f_dentry->d_inode); unsigned short flags = filp->f_flags; @@ -1905,7 +1905,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, loff_ * tape device again. The driver will detect an exception status in (No Cartridge) * and force a rewind. After that tar may continue writing. */ -static ssize_t qic02_tape_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) +static ssize_t qic02_tape_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) { int type = iminor(filp->f_dentry->d_inode); unsigned short flags = filp->f_flags; @@ -2400,6 +2400,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int struct mtop operation; unsigned char blk_addr[6]; struct mtpos ioctl_tell; + void __user *argp = (void __user *)ioarg; if (TP_DIAGS(current_type)) @@ -2416,7 +2417,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int if (c == _IOC_NR(MTIOCGETCONFIG)) { CHECK_IOC_SIZE(mtconfiginfo); - if (copy_to_user((char *) ioarg, (char *) &qic02_tape_dynconf, sizeof(qic02_tape_dynconf))) + if (copy_to_user(argp, &qic02_tape_dynconf, sizeof(qic02_tape_dynconf))) return -EFAULT; return 0; } else if (c == _IOC_NR(MTIOCSETCONFIG)) { @@ -2438,7 +2439,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int qic02_release_resources(); /* and go zombie */ /* copy struct from user space to kernel space */ - if (copy_from_user((char *) &qic02_tape_dynconf, (char *) ioarg, sizeof(qic02_tape_dynconf))) + if (copy_from_user(&qic02_tape_dynconf, argp, sizeof(qic02_tape_dynconf))) return -EFAULT; return update_ifc_masks(qic02_tape_dynconf.ifc_type); @@ -2452,7 +2453,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int CHECK_IOC_SIZE(mtop); /* copy mtop struct from user space to kernel space */ - if (copy_from_user((char *) &operation, (char *) ioarg, sizeof(operation))) + if (copy_from_user(&operation, argp, sizeof(operation))) return -EFAULT; /* ---note: mt_count is signed, negative seeks must be @@ -2507,7 +2508,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int */ /* copy results to user space */ - if (copy_to_user((char *) ioarg, (char *) &ioctl_status, sizeof(ioctl_status))) + if (copy_to_user(argp, &ioctl_status, sizeof(ioctl_status))) return -EFAULT; return 0; } else if (TP_HAVE_TELL && (c == _IOC_NR(MTIOCPOS))) { @@ -2527,7 +2528,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5]; /* copy results to user space */ - if (copy_to_user((char *) ioarg, (char *) &ioctl_tell, sizeof(ioctl_tell))) + if (copy_to_user(argp, &ioctl_tell, sizeof(ioctl_tell))) return -EFAULT; return 0; @@ -2536,7 +2537,7 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int } /* qic02_tape_ioctl */ -static ssize_t qic02_do_tape_read(struct file *filp, char *buf, size_t count, loff_t * ppos) +static ssize_t qic02_do_tape_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) { int err; @@ -2547,7 +2548,7 @@ static ssize_t qic02_do_tape_read(struct file *filp, char *buf, size_t count, lo return err; } -static ssize_t qic02_do_tape_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) +static ssize_t qic02_do_tape_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) { int err; diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c new file mode 100644 index 000000000..79493650f --- /dev/null +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -0,0 +1,233 @@ +/* + * drivers/watchdog/ixp4xx_wdt.c + * + * Watchdog driver for Intel IXP4xx network processors + * + * Author: Deepak Saxena + * + * Copyright 2004 (c) MontaVista, Software, Inc. + * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin + * + * 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 + +#include +#include +#include + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +static int heartbeat = 60; /* (secs) Default is 1 minute */ +static unsigned long wdt_status; +static unsigned long boot_status; + +#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) + +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 + +static void +wdt_enable(void) +{ + *IXP4XX_OSWK = IXP4XX_WDT_KEY; + *IXP4XX_OSWE = 0; + *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; + *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; + *IXP4XX_OSWK = 0; +} + +static void +wdt_disable(void) +{ + *IXP4XX_OSWK = IXP4XX_WDT_KEY; + *IXP4XX_OSWE = 0; + *IXP4XX_OSWK = 0; +} + +static int +ixp4xx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + wdt_enable(); + + return 0; +} + +static ssize_t +ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + wdt_enable(); + } + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | + WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "IXP4xx Watchdog", +}; + + +static int +ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -ENOIOCTLCMD; + int time; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(boot_status, (int *)arg); + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(time, (int *)arg); + if (ret) + break; + + if (time <= 0 || time > 60) { + ret = -EINVAL; + break; + } + + heartbeat = time; + wdt_enable(); + /* Fall through */ + + case WDIOC_GETTIMEOUT: + ret = put_user(heartbeat, (int *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_enable(); + ret = 0; + break; + } + return ret; +} + +static int +ixp4xx_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { + wdt_disable(); + } else { + printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - " + "timer will not stop\n"); + } + + clear_bit(WDT_IN_USE, &wdt_status); + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + return 0; +} + + +static struct file_operations ixp4xx_wdt_fops = +{ + .owner = THIS_MODULE, + .write = ixp4xx_wdt_write, + .ioctl = ixp4xx_wdt_ioctl, + .open = ixp4xx_wdt_open, + .release = ixp4xx_wdt_release, +}; + +static struct miscdevice ixp4xx_wdt_miscdev = +{ + .minor = WATCHDOG_MINOR, + .name = "IXP4xx Watchdog", + .fops = &ixp4xx_wdt_fops, +}; + +static int __init ixp4xx_wdt_init(void) +{ + int ret; + unsigned long processor_id; + + asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); + if (!(processor_id & 0xf)) { + printk("IXP4XXX Watchdog: Rev. A0 CPU detected - " + "watchdog disabled\n"); + + return -ENODEV; + } + + ret = misc_register(&ixp4xx_wdt_miscdev); + if (ret == 0) + printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat); + + boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? + WDIOF_CARDRESET : 0; + + return ret; +} + +static void __exit ixp4xx_wdt_exit(void) +{ + misc_deregister(&ixp4xx_wdt_miscdev); +} + + +module_init(ixp4xx_wdt_init); +module_exit(ixp4xx_wdt_exit); + +MODULE_AUTHOR("Deepak Saxena ); +MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index bd24b5348..295e11461 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -70,7 +70,7 @@ #include #include -#define WD_VER "1.16 (03/27/2004)" +#define WD_VER "1.16 (06/12/2004)" #define PFX "pcwd: " /* @@ -299,10 +299,11 @@ static int pcwd_stop(void) return 0; } -static void pcwd_keepalive(void) +static int pcwd_keepalive(void) { /* user land ping */ next_heartbeat = jiffies + (heartbeat * HZ); + return 0; } static int pcwd_set_heartbeat(int t) @@ -404,6 +405,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, int status; int temperature; int new_heartbeat; + int __user *argp = (int __user *)arg; static struct watchdog_info ident = { .options = WDIOF_OVERHEAT | WDIOF_CARDRESET | @@ -419,27 +421,27 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: - if(copy_to_user((void*)arg, &ident, sizeof(ident))) + if(copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: pcwd_get_status(&status); - return put_user(status, (int *) arg); + return put_user(status, argp); case WDIOC_GETBOOTSTATUS: - return put_user(initial_status, (int *) arg); + return put_user(initial_status, argp); case WDIOC_GETTEMP: if (pcwd_get_temperature(&temperature)) return -EFAULT; - return put_user(temperature, (int *) arg); + return put_user(temperature, argp); case WDIOC_SETOPTIONS: if (revision == PCWD_REVISION_C) { - if(copy_from_user(&rv, (int*) arg, sizeof(int))) + if(copy_from_user(&rv, argp, sizeof(int))) return -EFAULT; if (rv & WDIOS_DISABLECARD) @@ -464,7 +466,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, return 0; case WDIOC_SETTIMEOUT: - if (get_user(new_heartbeat, (int *) arg)) + if (get_user(new_heartbeat, argp)) return -EFAULT; if (pcwd_set_heartbeat(new_heartbeat)) @@ -474,13 +476,13 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, /* Fall */ case WDIOC_GETTIMEOUT: - return put_user(heartbeat, (int *)arg); + return put_user(heartbeat, argp); } return 0; } -static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, +static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { /* Can't seek (pwrite) on this device */ @@ -528,12 +530,12 @@ static int pcwd_close(struct inode *inode, struct file *file) { if (expect_close == 42) { pcwd_stop(); - atomic_inc( &open_allowed ); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); pcwd_keepalive(); } expect_close = 0; + atomic_inc( &open_allowed ); return 0; } @@ -541,7 +543,7 @@ static int pcwd_close(struct inode *inode, struct file *file) * /dev/temperature handling */ -static ssize_t pcwd_temp_read(struct file *file, char *buf, size_t count, +static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int temperature; diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index e24694c3e..0b3c727e5 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -49,7 +49,7 @@ /* Module and version information */ #define WATCHDOG_VERSION "1.00" -#define WATCHDOG_DATE "13/03/2004" +#define WATCHDOG_DATE "12 Jun 2004" #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" #define WATCHDOG_NAME "pcwd_pci" #define PFX WATCHDOG_NAME ": " @@ -73,7 +73,7 @@ #define WD_PCI_TTRP 0x04 /* Temperature Trip status */ /* according to documentation max. time to process a command for the pci - watchdog card is 100 ms, so we give it 150 ms to do it's job */ + * watchdog card is 100 ms, so we give it 150 ms to do it's job */ #define PCI_COMMAND_TIMEOUT 150 /* Watchdog's internal commands */ @@ -404,8 +404,8 @@ static int pcipcwd_release(struct inode *inode, struct file *file) printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); pcipcwd_keepalive(); } - clear_bit(0, &is_active); expect_release = 0; + clear_bit(0, &is_active); return 0; } @@ -585,15 +585,12 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev, printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n"); /* Check that the heartbeat value is within it's range ; if not reset to the default */ - if (heartbeat < 1 || heartbeat > 0xFFFF) { - heartbeat = WATCHDOG_HEARTBEAT; + if (pcipcwd_set_heartbeat(heartbeat)) { + pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT); printk(KERN_INFO PFX "heartbeat value must be 0" #define DRIVER_DESC "Berkshire USB-PC Watchdog driver" #define DRIVER_LICENSE "GPL" @@ -456,8 +457,8 @@ static int usb_pcwd_release(struct inode *inode, struct file *file) printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); usb_pcwd_keepalive(usb_pcwd_device); } - clear_bit(0, &is_active); expect_release = 0; + clear_bit(0, &is_active); return 0; } @@ -681,15 +682,12 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi ((option_switches & 0x08) ? "ON" : "OFF")); /* Check that the heartbeat value is within it's range ; if not reset to the default */ - if (heartbeat < 1 || heartbeat > 0xFFFF) { - heartbeat = WATCHDOG_HEARTBEAT; + if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) { + usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT); printk(KERN_INFO PFX "heartbeat value must be 0exists = 0; /* Deregister */ - misc_deregister(&usb_pcwd_temperature_miscdev); misc_deregister(&usb_pcwd_miscdev); + misc_deregister(&usb_pcwd_temperature_miscdev); unregister_reboot_notifier(&usb_pcwd_notifier); up (&usb_pcwd->sem); @@ -791,7 +789,7 @@ static int __init usb_pcwd_init(void) return result; } - printk(KERN_INFO PFX DRIVER_DESC " " DRIVER_VERSION "\n"); + printk(KERN_INFO PFX DRIVER_DESC " v" DRIVER_VERSION " (" DRIVER_DATE ")\n"); return 0; } diff --git a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c index 81d58c7b7..a0eaf6f1d 100644 --- a/drivers/cpufreq/proc_intf.c +++ b/drivers/cpufreq/proc_intf.c @@ -164,7 +164,7 @@ end: */ static int cpufreq_proc_write ( struct file *file, - const char *buffer, + const char __user *buffer, unsigned long count, void *data) { diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c new file mode 100644 index 000000000..d8bfd59c1 --- /dev/null +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -0,0 +1,181 @@ +/* + * drivers/i2c/i2c-adap-ixp4xx.c + * + * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have + * an on board I2C controller but provide 16 GPIO pins that are often + * used to create an I2C bus. This driver provides an i2c_adapter + * interface that plugs in under algo_bit and drives the GPIO pins + * as instructed by the alogorithm driver. + * + * Author: Deepak Saxena + * + * Copyright (c) 2003-2004 MontaVista Software Inc. + * + * 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. + * + * NOTE: Since different platforms will use different GPIO pins for + * I2C, this driver uses an IXP4xx-specific platform_data + * pointer to pass the GPIO numbers to the driver. This + * allows us to support all the different IXP4xx platforms + * w/o having to put #ifdefs in this driver. + * + * See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a + * device list and filling in the ixp4xx_i2c_pins data structure + * that is passed as the platform_data to this driver. + */ + +#include +#ifdef CONFIG_I2C_DEBUG_BUS +#define DEBUG 1 +#endif + +#include +#include +#include +#include +#include +#include + +#include /* Pick up IXP4xx-specific bits */ + +static inline int ixp4xx_scl_pin(void *data) +{ + return ((struct ixp4xx_i2c_pins*)data)->scl_pin; +} + +static inline int ixp4xx_sda_pin(void *data) +{ + return ((struct ixp4xx_i2c_pins*)data)->sda_pin; +} + +static void ixp4xx_bit_setscl(void *data, int val) +{ + gpio_line_set(ixp4xx_scl_pin(data), 0); + gpio_line_config(ixp4xx_scl_pin(data), + val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); +} + +static void ixp4xx_bit_setsda(void *data, int val) +{ + gpio_line_set(ixp4xx_sda_pin(data), 0); + gpio_line_config(ixp4xx_sda_pin(data), + val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); +} + +static int ixp4xx_bit_getscl(void *data) +{ + int scl; + + gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN ); + gpio_line_get(ixp4xx_scl_pin(data), &scl); + + return scl; +} + +static int ixp4xx_bit_getsda(void *data) +{ + int sda; + + gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN ); + gpio_line_get(ixp4xx_sda_pin(data), &sda); + + return sda; +} + +struct ixp4xx_i2c_data { + struct ixp4xx_i2c_pins *gpio_pins; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo_data; +}; + +static int ixp4xx_i2c_remove(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp4xx_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev); + + dev_set_drvdata(&plat_dev->dev, NULL); + + i2c_bit_del_bus(&drv_data->adapter); + + kfree(drv_data); + + return 0; +} + +static int ixp4xx_i2c_probe(struct device *dev) +{ + int err; + struct platform_device *plat_dev = to_platform_device(dev); + struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data; + struct ixp4xx_i2c_data *drv_data = + kmalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); + + if(!drv_data) + return -ENOMEM; + + memzero(drv_data, sizeof(struct ixp4xx_i2c_data)); + drv_data->gpio_pins = gpio; + + /* + * We could make a lot of these structures static, but + * certain platforms may have multiple GPIO-based I2C + * buses for various device domains, so we need per-device + * algo_data->data. + */ + drv_data->algo_data.data = gpio; + drv_data->algo_data.setsda = ixp4xx_bit_setsda; + drv_data->algo_data.setscl = ixp4xx_bit_setscl; + drv_data->algo_data.getsda = ixp4xx_bit_getsda; + drv_data->algo_data.getscl = ixp4xx_bit_getscl; + drv_data->algo_data.udelay = 10; + drv_data->algo_data.mdelay = 10; + drv_data->algo_data.timeout = 100; + + drv_data->adapter.id = I2C_HW_B_IXP4XX, + drv_data->adapter.algo_data = &drv_data->algo_data, + + drv_data->adapter.dev.parent = &plat_dev->dev; + + gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN); + gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN); + gpio_line_set(gpio->scl_pin, 0); + gpio_line_set(gpio->sda_pin, 0); + + if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) { + printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id); + + kfree(drv_data); + return err; + } + + dev_set_drvdata(&plat_dev->dev, drv_data); + + return 0; +} + +static struct device_driver ixp4xx_i2c_driver = { + .name = "IXP4XX-I2C", + .bus = &platform_bus_type, + .probe = ixp4xx_i2c_probe, + .remove = ixp4xx_i2c_remove, +}; + +static int __init ixp4xx_i2c_init(void) +{ + return driver_register(&ixp4xx_i2c_driver); +} + +static void __exit ixp4xx_i2c_exit(void) +{ + driver_unregister(&ixp4xx_i2c_driver); +} + +module_init(ixp4xx_i2c_init); +module_exit(ixp4xx_i2c_exit); + +MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena "); + diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c new file mode 100644 index 000000000..0f8a5ac5c --- /dev/null +++ b/drivers/i2c/chips/max1619.c @@ -0,0 +1,378 @@ +/* + * max1619.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2004 Alexey Fisher + * Jean Delvare + * + * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. + * It reports up to two temperatures (its own plus up to + * one external one). Complete datasheet can be + * obtained from Maxim's website at: + * http://pdfserv.maxim-ic.com/en/ds/MAX1619.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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include + + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, + 0x4c, 0x4e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(max1619); + +/* + * The MAX1619 registers + */ + +#define MAX1619_REG_R_MAN_ID 0xFE +#define MAX1619_REG_R_CHIP_ID 0xFF +#define MAX1619_REG_R_CONFIG 0x03 +#define MAX1619_REG_W_CONFIG 0x09 +#define MAX1619_REG_R_CONVRATE 0x04 +#define MAX1619_REG_W_CONVRATE 0x0A +#define MAX1619_REG_R_STATUS 0x02 +#define MAX1619_REG_R_LOCAL_TEMP 0x00 +#define MAX1619_REG_R_REMOTE_TEMP 0x01 +#define MAX1619_REG_R_REMOTE_HIGH 0x07 +#define MAX1619_REG_W_REMOTE_HIGH 0x0D +#define MAX1619_REG_R_REMOTE_LOW 0x08 +#define MAX1619_REG_W_REMOTE_LOW 0x0E +#define MAX1619_REG_R_REMOTE_CRIT 0x10 +#define MAX1619_REG_W_REMOTE_CRIT 0x12 +#define MAX1619_REG_R_TCRIT_HYST 0x11 +#define MAX1619_REG_W_TCRIT_HYST 0x13 + +/* + * Conversions and various macros + */ + +#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) +#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000) + +/* + * Functions declaration + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter); +static int max1619_detect(struct i2c_adapter *adapter, int address, + int kind); +static void max1619_init_client(struct i2c_client *client); +static int max1619_detach_client(struct i2c_client *client); +static struct max1619_data *max1619_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver max1619_driver = { + .owner = THIS_MODULE, + .name = "max1619", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max1619_attach_adapter, + .detach_client = max1619_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct max1619_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 temp_input1; /* local */ + u8 temp_input2, temp_low2, temp_high2; /* remote */ + u8 temp_crit2; + u8 temp_hyst2; + u8 alarms; +}; + +/* + * Internal variables + */ + +static int max1619_id = 0; + +/* + * Sysfs stuff + */ + +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct max1619_data *data = max1619_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show_temp(temp_input1); +show_temp(temp_input2); +show_temp(temp_low2); +show_temp(temp_high2); +show_temp(temp_crit2); +show_temp(temp_hyst2); + +#define set_temp2(value, reg) \ +static ssize_t set_##value(struct device *dev, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct max1619_data *data = i2c_get_clientdata(client); \ + data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \ + i2c_smbus_write_byte_data(client, reg, data->value); \ + return count; \ +} + +set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); +set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); +set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); +set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); + +static ssize_t show_alarms(struct device *dev, char *buf) +{ + struct max1619_data *data = max1619_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, + set_temp_low2); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, + set_temp_high2); +static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, + set_temp_crit2); +static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, + set_temp_hyst2); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, max1619_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct max1619_data *data; + int err = 0; + const char *name = ""; + u8 reg_config=0, reg_convrate=0, reg_status=0; + u8 man_id, chip_id; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct max1619_data)); + + /* The common I2C client data is placed right before the + MAX1619-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &max1619_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + reg_config = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONFIG); + reg_convrate = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONVRATE); + reg_status = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_STATUS); + if ((reg_config & 0x03) != 0x00 + || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) { + dev_dbg(&adapter->dev, + "MAX1619 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + + man_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CHIP_ID); + + if ((man_id == 0x4D) && (chip_id == 0x04)){ + kind = max1619; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + + + if (kind == max1619){ + name = "max1619"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + new_client->id = max1619_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the MAX1619 chip */ + max1619_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void max1619_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (config & 0x40) + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, + config & 0xBF); /* run */ +} + +static int max1619_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct max1619_data *max1619_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ * 2) || + (jiffies < data->last_updated) || + !data->valid) { + + dev_dbg(&client->dev, "Updating max1619 data.\n"); + data->temp_input1 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_LOCAL_TEMP); + data->temp_input2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TEMP); + data->temp_high2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_HIGH); + data->temp_low2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_LOW); + data->temp_crit2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_CRIT); + data->temp_hyst2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_TCRIT_HYST); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_max1619_init(void) +{ + return i2c_add_driver(&max1619_driver); +} + +static void __exit sensors_max1619_exit(void) +{ + i2c_del_driver(&max1619_driver); +} + +MODULE_AUTHOR("Alexey Fisher and" + "Jean Delvare "); +MODULE_DESCRIPTION("MAX1619 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_max1619_init); +module_exit(sensors_max1619_exit); diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c new file mode 100644 index 000000000..0fa55d45e --- /dev/null +++ b/drivers/i2c/chips/rtc8564.c @@ -0,0 +1,396 @@ +/* + * linux/drivers/i2c/chips/rtc8564.c + * + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * 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. + * + * Driver for system3's EPSON RTC 8564 chip + */ +#include +#include +#include +#include +#include +#include /* get the user-level API */ +#include +#include + +#include "rtc8564.h" + +#ifdef DEBUG +# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0); +#else +# define _DBG(x, fmt, args...) do { } while(0); +#endif + +#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \ + "mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \ + (rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \ + (rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl); + +struct rtc8564_data { + struct i2c_client client; + u16 ctrl; +}; + +static inline u8 _rtc8564_ctrl1(struct i2c_client *client) +{ + struct rtc8564_data *data = i2c_get_clientdata(client); + return data->ctrl & 0xff; +} +static inline u8 _rtc8564_ctrl2(struct i2c_client *client) +{ + struct rtc8564_data *data = i2c_get_clientdata(client); + return (data->ctrl & 0xff00) >> 8; +} + +#define CTRL1(c) _rtc8564_ctrl1(c) +#define CTRL2(c) _rtc8564_ctrl2(c) + +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) + +static int debug = 0; +MODULE_PARM(debug, "i"); + +static struct i2c_driver rtc8564_driver; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .normal_i2c_range = ignore, + .probe = ignore, + .probe_range = ignore, + .ignore = ignore, + .ignore_range = ignore, + .force = ignore, +}; + +static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem); +static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem); + +static int rtc8564_read(struct i2c_client *client, unsigned char adr, + unsigned char *buf, unsigned char len) +{ + int ret = -EIO; + unsigned char addr[1] = { adr }; + struct i2c_msg msgs[2] = { + {client->addr, 0, 1, addr}, + {client->addr, I2C_M_RD, len, buf} + }; + + _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len); + + if (!buf || !client) { + ret = -EINVAL; + goto done; + } + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret == 2) { + ret = 0; + } + +done: + return ret; +} + +static int rtc8564_write(struct i2c_client *client, unsigned char adr, + unsigned char *data, unsigned char len) +{ + int ret = 0; + unsigned char _data[16]; + struct i2c_msg wr; + int i; + + if (!client || !data || len > 15) { + ret = -EINVAL; + goto done; + } + + _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len); + + _data[0] = adr; + for (i = 0; i < len; i++) { + _data[i + 1] = data[i]; + _DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]); + } + + wr.addr = client->addr; + wr.flags = 0; + wr.len = len + 1; + wr.buf = _data; + + ret = i2c_transfer(client->adapter, &wr, 1); + if (ret == 1) { + ret = 0; + } + +done: + return ret; +} + +static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int ret; + struct i2c_client *new_client; + struct rtc8564_data *d; + unsigned char data[10]; + unsigned char ad[1] = { 0 }; + struct i2c_msg ctrl_wr[1] = { + {addr, 0, 2, data} + }; + struct i2c_msg ctrl_rd[2] = { + {addr, 0, 1, ad}, + {addr, I2C_M_RD, 2, data} + }; + + d = kmalloc(sizeof(struct rtc8564_data), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto done; + } + memset(d, 0, sizeof(struct rtc8564_data)); + new_client = &d->client; + + strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); + i2c_set_clientdata(new_client, d); + new_client->id = rtc8564_driver.id; + new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY; + new_client->addr = addr; + new_client->adapter = adap; + new_client->driver = &rtc8564_driver; + + _DBG(1, "client=%p", new_client); + _DBG(1, "client.id=%d", new_client->id); + + /* init ctrl1 reg */ + data[0] = 0; + data[1] = 0; + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "rtc8564: cant init ctrl1\n"); + ret = -ENODEV; + goto done; + } + + /* read back ctrl1 and ctrl2 */ + ret = i2c_transfer(new_client->adapter, ctrl_rd, 2); + if (ret != 2) { + printk(KERN_INFO "rtc8564: cant read ctrl\n"); + ret = -ENODEV; + goto done; + } + + d->ctrl = data[0] | (data[1] << 8); + + _DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x", + data[0], data[1]); + + ret = i2c_attach_client(new_client); +done: + if (ret) { + kfree(d); + } + return ret; +} + +static int rtc8564_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, rtc8564_attach); +} + +static int rtc8564_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt) +{ + int ret = -EIO; + unsigned char buf[15]; + + _DBG(1, "client=%p, dt=%p", client, dt); + + if (!dt || !client) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + + ret = rtc8564_read(client, 0, buf, 15); + if (ret) + return ret; + + /* century stored in minute alarm reg */ + dt->year = BCD_TO_BIN(buf[RTC8564_REG_YEAR]); + dt->year += 100 * BCD_TO_BIN(buf[RTC8564_REG_AL_MIN] & 0x3f); + dt->mday = BCD_TO_BIN(buf[RTC8564_REG_DAY] & 0x3f); + dt->wday = BCD_TO_BIN(buf[RTC8564_REG_WDAY] & 7); + dt->mon = BCD_TO_BIN(buf[RTC8564_REG_MON_CENT] & 0x1f); + + dt->secs = BCD_TO_BIN(buf[RTC8564_REG_SEC] & 0x7f); + dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80; + dt->mins = BCD_TO_BIN(buf[RTC8564_REG_MIN] & 0x7f); + dt->hours = BCD_TO_BIN(buf[RTC8564_REG_HR] & 0x3f); + + _DBGRTCTM(2, *dt); + + return 0; +} + +static int +rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) +{ + int ret, len = 5; + unsigned char buf[15]; + + _DBG(1, "client=%p, dt=%p", client, dt); + + if (!dt || !client) + return -EINVAL; + + _DBGRTCTM(2, *dt); + + buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP; + buf[RTC8564_REG_CTRL2] = CTRL2(client); + buf[RTC8564_REG_SEC] = BIN_TO_BCD(dt->secs); + buf[RTC8564_REG_MIN] = BIN_TO_BCD(dt->mins); + buf[RTC8564_REG_HR] = BIN_TO_BCD(dt->hours); + + if (datetoo) { + len += 5; + buf[RTC8564_REG_DAY] = BIN_TO_BCD(dt->mday); + buf[RTC8564_REG_WDAY] = BIN_TO_BCD(dt->wday); + buf[RTC8564_REG_MON_CENT] = BIN_TO_BCD(dt->mon) & 0x1f; + /* century stored in minute alarm reg */ + buf[RTC8564_REG_YEAR] = BIN_TO_BCD(dt->year % 100); + buf[RTC8564_REG_AL_MIN] = BIN_TO_BCD(dt->year / 100); + } + + ret = rtc8564_write(client, 0, buf, len); + if (ret) { + _DBG(1, "error writing data! %d", ret); + } + + buf[RTC8564_REG_CTRL1] = CTRL1(client); + ret = rtc8564_write(client, 0, buf, 1); + if (ret) { + _DBG(1, "error writing data! %d", ret); + } + + return ret; +} + +static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl) +{ + struct rtc8564_data *data = i2c_get_clientdata(client); + + if (!ctrl || !client) + return -1; + + *ctrl = data->ctrl; + return 0; +} + +static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl) +{ + struct rtc8564_data *data = i2c_get_clientdata(client); + unsigned char buf[2]; + + if (!ctrl || !client) + return -1; + + buf[0] = *ctrl & 0xff; + buf[1] = (*ctrl & 0xff00) >> 8; + data->ctrl = *ctrl; + + return rtc8564_write(client, 0, buf, 2); +} + +static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem) +{ + + if (!mem || !client) + return -EINVAL; + + return rtc8564_read(client, mem->loc, mem->data, mem->nr); +} + +static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem) +{ + + if (!mem || !client) + return -EINVAL; + + return rtc8564_write(client, mem->loc, mem->data, mem->nr); +} + +static int +rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + + _DBG(1, "cmd=%d", cmd); + + switch (cmd) { + case RTC_GETDATETIME: + return rtc8564_get_datetime(client, arg); + + case RTC_SETTIME: + return rtc8564_set_datetime(client, arg, 0); + + case RTC_SETDATETIME: + return rtc8564_set_datetime(client, arg, 1); + + case RTC_GETCTRL: + return rtc8564_get_ctrl(client, arg); + + case RTC_SETCTRL: + return rtc8564_set_ctrl(client, arg); + + case MEM_READ: + return rtc8564_read_mem(client, arg); + + case MEM_WRITE: + return rtc8564_write_mem(client, arg); + + default: + return -EINVAL; + } +} + +static struct i2c_driver rtc8564_driver = { + .owner = THIS_MODULE, + .name = "RTC8564", + .id = I2C_DRIVERID_RTC8564, + .flags = I2C_DF_NOTIFY, + .attach_adapter = rtc8564_probe, + .detach_client = rtc8564_detach, + .command = rtc8564_command +}; + +static __init int rtc8564_init(void) +{ + return i2c_add_driver(&rtc8564_driver); +} + +static __exit void rtc8564_exit(void) +{ + i2c_del_driver(&rtc8564_driver); +} + +MODULE_AUTHOR("Stefan Eletzhofer "); +MODULE_DESCRIPTION("EPSON RTC8564 Driver"); +MODULE_LICENSE("GPL"); + +module_init(rtc8564_init); +module_exit(rtc8564_exit); diff --git a/drivers/i2c/chips/rtc8564.h b/drivers/i2c/chips/rtc8564.h new file mode 100644 index 000000000..e5342d10b --- /dev/null +++ b/drivers/i2c/chips/rtc8564.h @@ -0,0 +1,78 @@ +/* + * linux/drivers/i2c/chips/rtc8564.h + * + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.h + * Copyright (C) 2000 Russell King + * + * 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. + */ +struct rtc_tm { + unsigned char secs; + unsigned char mins; + unsigned char hours; + unsigned char mday; + unsigned char mon; + unsigned short year; /* xxxx 4 digits :) */ + unsigned char wday; + unsigned char vl; +}; + +struct mem { + unsigned int loc; + unsigned int nr; + unsigned char *data; +}; + +#define RTC_GETDATETIME 0 +#define RTC_SETTIME 1 +#define RTC_SETDATETIME 2 +#define RTC_GETCTRL 3 +#define RTC_SETCTRL 4 +#define MEM_READ 5 +#define MEM_WRITE 6 + +#define RTC8564_REG_CTRL1 0x0 /* T 0 S 0 | T 0 0 0 */ +#define RTC8564_REG_CTRL2 0x1 /* 0 0 0 TI/TP | AF TF AIE TIE */ +#define RTC8564_REG_SEC 0x2 /* VL 4 2 1 | 8 4 2 1 */ +#define RTC8564_REG_MIN 0x3 /* x 4 2 1 | 8 4 2 1 */ +#define RTC8564_REG_HR 0x4 /* x x 2 1 | 8 4 2 1 */ +#define RTC8564_REG_DAY 0x5 /* x x 2 1 | 8 4 2 1 */ +#define RTC8564_REG_WDAY 0x6 /* x x x x | x 4 2 1 */ +#define RTC8564_REG_MON_CENT 0x7 /* C x x 1 | 8 4 2 1 */ +#define RTC8564_REG_YEAR 0x8 /* 8 4 2 1 | 8 4 2 1 */ +#define RTC8564_REG_AL_MIN 0x9 /* AE 4 2 1 | 8 4 2 1 */ +#define RTC8564_REG_AL_HR 0xa /* AE 4 2 1 | 8 4 2 1 */ +#define RTC8564_REG_AL_DAY 0xb /* AE x 2 1 | 8 4 2 1 */ +#define RTC8564_REG_AL_WDAY 0xc /* AE x x x | x 4 2 1 */ +#define RTC8564_REG_CLKOUT 0xd /* FE x x x | x x FD1 FD0 */ +#define RTC8564_REG_TCTL 0xe /* TE x x x | x x FD1 FD0 */ +#define RTC8564_REG_TIMER 0xf /* 8 bit binary */ + +/* Control reg */ +#define RTC8564_CTRL1_TEST1 (1<<3) +#define RTC8564_CTRL1_STOP (1<<5) +#define RTC8564_CTRL1_TEST2 (1<<7) + +#define RTC8564_CTRL2_TIE (1<<0) +#define RTC8564_CTRL2_AIE (1<<1) +#define RTC8564_CTRL2_TF (1<<2) +#define RTC8564_CTRL2_AF (1<<3) +#define RTC8564_CTRL2_TI_TP (1<<4) + +/* CLKOUT frequencies */ +#define RTC8564_FD_32768HZ (0x0) +#define RTC8564_FD_1024HZ (0x1) +#define RTC8564_FD_32 (0x2) +#define RTC8564_FD_1HZ (0x3) + +/* Timer CTRL */ +#define RTC8564_TD_4096HZ (0x0) +#define RTC8564_TD_64HZ (0x1) +#define RTC8564_TD_1HZ (0x2) +#define RTC8564_TD_1_60HZ (0x3) + +#define I2C_DRIVERID_RTC8564 0xf000 diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c new file mode 100644 index 000000000..fb91cb8bf --- /dev/null +++ b/drivers/ide/h8300/ide-h8300.c @@ -0,0 +1,119 @@ +/* + * drivers/ide/ide-h8300.c + * H8/300 generic IDE interface + */ + +#include +#include +#include + +#include +#include + +#define bswap(d) \ +({ \ + u16 r; \ + __asm__("mov.b %w1,r1h\n\t" \ + "mov.b %x1,r1l\n\t" \ + "mov.w r1,%0" \ + :"=r"(r) \ + :"r"(d) \ + :"er1"); \ + (r); \ +}) + +static void mm_outw(u16 d, unsigned long a) +{ + __asm__("mov.b %w0,r2h\n\t" + "mov.b %x0,r2l\n\t" + "mov.w r2,@%1" + : + :"r"(d),"r"(a) + :"er2"); +} + +static u16 mm_inw(unsigned long a) +{ + register u16 r __asm__("er0"); + __asm__("mov.w @%1,r2\n\t" + "mov.b r2l,%x0\n\t" + "mov.b r2h,%w0" + :"=r"(r) + :"r"(a) + :"er2"); + return r; +} + +static void mm_outsw(unsigned long addr, void *buf, u32 len) +{ + unsigned short *bp = (unsigned short *)buf; + for (; len > 0; len--, bp++) + *(volatile u16 *)addr = bswap(*bp); +} + +static void mm_insw(unsigned long addr, void *buf, u32 len) +{ + unsigned short *bp = (unsigned short *)buf; + for (; len > 0; len--, bp++) + *bp = bswap(*(volatile u16 *)addr); +} + +#define H8300_IDE_GAP (2) + +static inline void hw_setup(hw_regs_t *hw) +{ + int i; + + memset(hw, 0, sizeof(hw_regs_t)); + for (i = 0; i <= IDE_STATUS_OFFSET; i++) + hw->io_ports[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i; + hw->io_ports[IDE_CONTROL_OFFSET] = CONFIG_H8300_IDE_ALT; + hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ; + hw->dma = NO_DMA; + hw->chipset = ide_generic; +} + +static inline void hwif_setup(ide_hwif_t *hwif) +{ + default_hwif_iops(hwif); + + hwif->mmio = 2; + hwif->OUTW = mm_outw; + hwif->OUTSW = mm_outsw; + hwif->INW = mm_inw; + hwif->INSW = mm_insw; + hwif->OUTL = NULL; + hwif->INL = NULL; + hwif->OUTSL = NULL; + hwif->INSL = NULL; +} + +void __init h8300_ide_init(void) +{ + hw_regs_t hw; + ide_hwif_t *hwif; + int idx; + + if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300")) + goto out_busy; + if (!request_region(CONFIG_H8300_IDE_ALT, H8300_IDE_GAP, "ide-h8300")) { + release_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8); + goto out_busy; + } + + hw_setup(&hw); + + /* register if */ + idx = ide_register_hw(&hw, &hwif); + if (idx == -1) { + printk(KERN_ERR "ide-h8300: IDE I/F register failed\n"); + return; + } + + hwif_setup(hwif); + printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx); + return; + +out_busy: + printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n"); +} diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 4f44c2976..19ae46dc0 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -513,9 +513,7 @@ int __ide_dma_off_quietly (ide_drive_t *drive) if (HWIF(drive)->ide_dma_host_off(drive)) return 1; -#ifdef CONFIG_BLK_DEV_IDE_TCQ - __ide_dma_queued_off(drive); -#endif + return 0; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index ae2d5b912..56fec5ca1 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1482,7 +1482,7 @@ static int idefloppy_get_capacity (ide_drive_t *drive) ** */ -static int idefloppy_get_format_capacities(ide_drive_t *drive, int *arg) +static int idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg) { idefloppy_pc_t pc; idefloppy_capacity_header_t *header; @@ -1490,7 +1490,7 @@ static int idefloppy_get_format_capacities(ide_drive_t *drive, int *arg) int i, descriptors, blocks, length; int u_array_size; int u_index; - int *argp; + int __user *argp; if (get_user(u_array_size, arg)) return (-EFAULT); @@ -1558,7 +1558,7 @@ static int idefloppy_get_format_capacities(ide_drive_t *drive, int *arg) ** 0x01 - verify media after format. */ -static int idefloppy_begin_format(ide_drive_t *drive, int *arg) +static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg) { int blocks; int length; @@ -1591,7 +1591,7 @@ static int idefloppy_begin_format(ide_drive_t *drive, int *arg) ** the dsc bit, and return either 0 or 65536. */ -static int idefloppy_get_format_progress(ide_drive_t *drive, int *arg) +static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg) { idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_pc_t pc; @@ -1945,6 +1945,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, struct block_device *bdev = inode->i_bdev; ide_drive_t *drive = bdev->bd_disk->private_data; idefloppy_floppy_t *floppy = drive->driver_data; + void __user *argp = (void __user *)arg; int err = generic_ide_ioctl(bdev, cmd, arg); int prevent = (arg) ? 1 : 0; idefloppy_pc_t pc; @@ -1972,7 +1973,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: return 0; case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: - return idefloppy_get_format_capacities(drive, (int *)arg); + return idefloppy_get_format_capacities(drive, argp); case IDEFLOPPY_IOCTL_FORMAT_START: if (!(file->f_mode & 2)) @@ -1988,7 +1989,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); - err = idefloppy_begin_format(drive, (int *)arg); + err = idefloppy_begin_format(drive, argp); if (err) clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); return err; @@ -1999,7 +2000,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, ** format progress reporting. */ case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: - return idefloppy_get_format_progress(drive, (int *)arg); + return idefloppy_get_format_progress(drive, argp); } return -EINVAL; } diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index 5b5db4781..6b9bcdb6c 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -16,25 +16,9 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include - #include - -#define GENERIC_HD_DATA 0 -#define GENERIC_HD_ERROR 1 -#define GENERIC_HD_NSECTOR 2 -#define GENERIC_HD_SECTOR 3 -#define GENERIC_HD_LCYL 4 -#define GENERIC_HD_HCYL 5 -#define GENERIC_HD_SELECT 6 -#define GENERIC_HD_STATUS 7 - -static int generic_ide_offsets[IDE_NR_PORTS] = { - GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, - GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL, - GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1 -}; +#include /* Add your devices here :)) */ struct pnp_device_id idepnp_devices[] = { @@ -52,12 +36,11 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0))) return -1; - ide_setup_ports(&hw, (unsigned long) pnp_port_start(dev, 0), - generic_ide_offsets, - (unsigned long) pnp_port_start(dev, 1), - 0, NULL, -// generic_pnp_ide_iops, - pnp_irq(dev, 0)); + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, pnp_port_start(dev, 0), + pnp_port_start(dev, 1)); + hw.irq = pnp_irq(dev, 0); + hw.dma = NO_DMA; index = ide_register_hw(&hw, &hwif); @@ -86,11 +69,7 @@ static struct pnp_driver idepnp_driver = { .remove = idepnp_remove, }; - -void pnpide_init(int enable) +void __init pnpide_init(void) { - if(enable) - pnp_register_driver(&idepnp_driver); - else - pnp_unregister_driver(&idepnp_driver); + pnp_register_driver(&idepnp_driver); } diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index eb51201ab..2a343679a 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -38,7 +38,7 @@ #include -#include "alim15x3.h" +#define DISPLAY_ALI_TIMINGS /* * ALi devices are not plug in. Otherwise these static values would @@ -853,6 +853,16 @@ static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } +static ide_pci_device_t ali15x3_chipset __devinitdata = { + .name = "ALI15X3", + .init_chipset = init_chipset_ali15x3, + .init_hwif = init_hwif_ali15x3, + .init_dma = init_dma_ali15x3, + .channels = 2, + .autodma = AUTODMA, + .bootable = ON_BOARD, +}; + /** * alim15x3_init_one - set up an ALi15x3 IDE controller * @dev: PCI device to set up @@ -863,8 +873,8 @@ static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data]; - + ide_pci_device_t *d = &ali15x3_chipset; + if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, NULL)) printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not yet fully tested.\n"); diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index c33cd8ee3..f9c9ab664 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -235,7 +235,7 @@ no_dma_set: */ #define HPT34X_PCI_INIT_REG 0x80 -static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const char *name) { int i = 0; unsigned long hpt34xIoBase = pci_resource_start(dev, 4); @@ -289,7 +289,7 @@ static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char return dev->irq; } -static void __init init_hwif_hpt34x (ide_hwif_t *hwif) +static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) { u16 pcicmd = 0; diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h index e7f1d30c6..e6734263a 100644 --- a/drivers/ieee1394/csr1212.h +++ b/drivers/ieee1394/csr1212.h @@ -38,9 +38,11 @@ #include #include #include +#include +#include -#define CSR1212_MALLOC(size) kmalloc((size), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) -#define CSR1212_FREE(ptr) kfree(ptr) +#define CSR1212_MALLOC(size) vmalloc((size)) +#define CSR1212_FREE(ptr) vfree(ptr) #define CSR1212_BE16_TO_CPU(quad) be16_to_cpu(quad) #define CSR1212_CPU_TO_BE16(quad) cpu_to_be16(quad) #define CSR1212_BE32_TO_CPU(quad) be32_to_cpu(quad) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index d99ac5dda..48a7c5049 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -89,7 +89,7 @@ #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) static char version[] __devinitdata = - "$Rev: 1198 $ Ben Collins "; + "$Rev: 1224 $ Ben Collins "; struct fragment_info { struct list_head list; @@ -191,7 +191,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr); +static int ether1394_ethtool_ioctl(struct net_device *dev, void __user *useraddr); static int ether1394_write(struct hpsb_host *host, int srcid, int destid, quadlet_t *data, u64 addr, size_t len, u16 flags); @@ -1770,7 +1770,7 @@ static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd { switch(cmd) { case SIOCETHTOOL: - return ether1394_ethtool_ioctl(dev, (void *) ifr->ifr_data); + return ether1394_ethtool_ioctl(dev, ifr->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIREG: /* Read MII PHY register. */ @@ -1782,18 +1782,18 @@ static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd return 0; } -static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int ether1394_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; - if (get_user(ethcmd, (u32 *)useraddr)) + if (get_user(ethcmd, (u32 __user *)useraddr)) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, driver_name); - strcpy (info.version, "$Rev: 1198 $"); + strcpy (info.version, "$Rev: 1224 $"); /* FIXME XXX provide sane businfo */ strcpy (info.bus_info, "ieee1394"); if (copy_to_user (useraddr, &info, sizeof (info))) diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c index 67fc9f7b6..50c403c6c 100644 --- a/drivers/ieee1394/highlevel.c +++ b/drivers/ieee1394/highlevel.c @@ -383,7 +383,7 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, a2sa = a2->start & align_mask; a2ea = (a2->end + alignment -1) & align_mask; - if ((a2sa - a1ea >= size) && (a2sa - start >= size) && (end - a1ea >= size)) { + if ((a2sa - a1ea >= size) && (a2sa - start >= size) && (a2sa > start)) { as->start = max(start, a1ea); as->end = as->start + size; list_add(&as->host_list, entry); diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index 000e44cab..739e76840 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -66,7 +66,7 @@ struct hpsb_host { struct class_device class_dev; int update_config_rom; - struct timer_list delayed_reset; + struct work_struct delayed_reset; unsigned int config_roms; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 88438b58b..afcf7f89e 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) static char version[] __devinitdata = - "$Rev: 1203 $ Ben Collins "; + "$Rev: 1223 $ Ben Collins "; /* Module Parameters */ static int phys_dma = 1; @@ -516,6 +516,12 @@ static void ohci_initialize(struct ti_ohci *ohci) ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); + if (ohci->max_packet_size < 512) { + HPSB_ERR("warning: Invalid max packet size of %d, setting to 512", + ohci->max_packet_size); + ohci->max_packet_size = 512; + } + /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index a9b92c1ed..7a757fc43 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -864,6 +864,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); + if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, @@ -926,6 +927,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); + if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, @@ -1009,6 +1011,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); + if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, @@ -1112,6 +1115,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); + if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index c31f5abcb..7eabb5f4e 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -35,7 +35,7 @@ #include MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input driver event debug module"); +MODULE_DESCRIPTION("Input driver event debug module"); MODULE_LICENSE("GPL"); static char evbug_name[] = "evbug"; @@ -67,7 +67,7 @@ static struct input_handle *evbug_connect(struct input_handler *handler, struct static void evbug_disconnect(struct input_handle *handle) { printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); - + input_close_device(handle); kfree(handle); @@ -79,7 +79,7 @@ static struct input_device_id evbug_ids[] = { }; MODULE_DEVICE_TABLE(input, evbug_ids); - + static struct input_handler evbug_handler = { .event = evbug_event, .connect = evbug_connect, diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c index 0ec91ea49..71fcad10c 100644 --- a/drivers/input/gameport/cs461x.c +++ b/drivers/input/gameport/cs461x.c @@ -1,8 +1,8 @@ /* - The all defines and part of code (such as cs461x_*) are - contributed from ALSA 0.5.8 sources. + The all defines and part of code (such as cs461x_*) are + contributed from ALSA 0.5.8 sources. See http://www.alsa-project.org/ for sources - + Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610 */ @@ -89,8 +89,8 @@ MODULE_LICENSE("GPL"); #define JSIO_BXOE 0x00000040 #define JSIO_BYOE 0x00000080 -/* - The card initialization code is obfuscated; the module cs461x +/* + The card initialization code is obfuscated; the module cs461x need to be loaded after ALSA modules initialized and something played on the CS 4610 chip (see sources for details of CS4610 initialization code from ALSA) @@ -112,7 +112,7 @@ MODULE_LICENSE("GPL"); #define BA1_DWORD_SIZE (13 * 1024 + 512) #define BA1_MEMORY_COUNT 3 -/* +/* Only one CS461x card is still suppoted; the code requires redesign to avoid this limitatuion. */ @@ -163,7 +163,7 @@ static int cs461x_free(struct pci_dev *pdev) if(port){ gameport_unregister_port(port); kfree(port); - } + } if (ba0) iounmap(ba0); #ifdef CS461X_FULL_MAP if (ba1.name.data0) iounmap(ba1.name.data0); @@ -187,13 +187,13 @@ static unsigned char cs461x_gameport_read(struct gameport *gameport) static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons) { unsigned js1, js2, jst; - + js1 = cs461x_peekBA0(BA0_JSC1); js2 = cs461x_peekBA0(BA0_JSC2); jst = cs461x_peekBA0(BA0_JSPT); - - *buttons = (~jst >> 4) & 0x0F; - + + *buttons = (~jst >> 4) & 0x0F; + axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; @@ -228,7 +228,7 @@ static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_dev { int rc; struct gameport* port; - + rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", @@ -240,7 +240,7 @@ static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_dev #ifdef CS461X_FULL_MAP ba1_addr = pci_resource_start(pdev, 1); #endif - if (ba0_addr == 0 || ba0_addr == ~0 + if (ba0_addr == 0 || ba0_addr == ~0 #ifdef CS461X_FULL_MAP || ba1_addr == 0 || ba1_addr == ~0 #endif @@ -281,7 +281,7 @@ static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_dev memset(port, 0, sizeof(struct gameport)); pci_set_drvdata(pdev, port); - + port->open = cs461x_gameport_open; port->trigger = cs461x_gameport_trigger; port->read = cs461x_gameport_read; @@ -310,7 +310,7 @@ static void __devexit cs461x_pci_remove(struct pci_dev *pdev) { cs461x_free(pdev); } - + static struct pci_driver cs461x_pci_driver = { .name = "CS461x Gameport", .id_table = cs461x_pci_tbl, diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index ec18fb32b..89d469378 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -48,7 +48,7 @@ struct emu { int size; char phys[32]; }; - + static struct pci_device_id emu_tbl[] = { { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ @@ -61,7 +61,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id { int ioport, iolen; struct emu *emu; - + if (pci_enable_device(pdev)) return -EBUSY; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 7cd7deb9c..ff3b620b8 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -111,7 +111,7 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device pci_set_drvdata(pci, gp); - outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ + outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ gameport_register_port(&gp->gameport); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 431883c5f..b2a68ab2a 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -168,7 +168,7 @@ int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode) return -1; gameport->dev = dev; - + return 0; } diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c index 8a8adb558..7d1d3832c 100644 --- a/drivers/input/gameport/lightning.c +++ b/drivers/input/gameport/lightning.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -106,7 +106,7 @@ static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons) result = 0; -fail: outb(L4_SELECT_ANALOG, L4_PORT); +fail: outb(L4_SELECT_ANALOG, L4_PORT); return result; } @@ -126,7 +126,7 @@ static int l4_open(struct gameport *gameport, int mode) static int l4_getcal(int port, int *cal) { int i, result = -1; - + outb(L4_SELECT_ANALOG, L4_PORT); outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT); @@ -208,7 +208,7 @@ static int l4_calibrate(struct gameport *gameport, int *axes, int *max) return 0; } - + static int __init l4_init(void) { int cal[4] = {255,255,255,255}; @@ -266,7 +266,7 @@ static int __init l4_init(void) if (rev > 0x28) /* on 2.9+ the setcal command works correctly */ l4_setcal(l4->port, cal); - + gameport_register_port(gameport); } diff --git a/drivers/input/input.c b/drivers/input/input.c index 41bb52187..73b17418a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -106,7 +106,7 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in } break; - + case EV_ABS: if (code > ABS_MAX || !test_bit(code, dev->absbit)) @@ -144,27 +144,27 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in if (code > MSC_MAX || !test_bit(code, dev->mscbit)) return; - if (dev->event) dev->event(dev, type, code, value); - + if (dev->event) dev->event(dev, type, code, value); + break; case EV_LED: - + if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) return; change_bit(code, dev->led); - if (dev->event) dev->event(dev, type, code, value); - + if (dev->event) dev->event(dev, type, code, value); + break; case EV_SND: - + if (code > SND_MAX || !test_bit(code, dev->sndbit)) return; - if (dev->event) dev->event(dev, type, code, value); - + if (dev->event) dev->event(dev, type, code, value); + break; case EV_REP: @@ -181,7 +181,7 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in break; } - if (type != EV_SYN) + if (type != EV_SYN) dev->sync = 0; if (dev->grab) @@ -282,11 +282,11 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id->id.vendor != dev->id.vendor) continue; - + if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id->id.product != dev->id.product) continue; - + if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id->id.version != dev->id.version) continue; @@ -351,11 +351,11 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) } if (in_interrupt()) { printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); - return; + return; } if (!current->fs->root) { printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); - return; + return; } if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); @@ -381,17 +381,17 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) envp[i++] = scratch; scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; - + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; + if (dev->name) { envp[i++] = scratch; - scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; + scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; } if (dev->phys) { envp[i++] = scratch; - scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; - } + scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; + } SPRINTF_BIT_A(evbit, "EV=", EV_MAX); SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); @@ -506,7 +506,7 @@ void input_register_handler(struct input_handler *handler) input_table[handler->minor >> 5] = handler; list_add_tail(&handler->node, &input_handler_list); - + list_for_each_entry(dev, &input_dev_list, node) if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if ((id = input_match_device(handler->id_table, dev))) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index abc2e107e..3cc849e03 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -1,12 +1,12 @@ /* * Joystick device driver for the input driver suite. * - * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 1999 Colin Van Dyke + * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 1999 Colin Van Dyke * * 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 + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ @@ -34,7 +34,7 @@ MODULE_SUPPORTED_DEVICE("input/js"); MODULE_LICENSE("GPL"); #define JOYDEV_MINOR_BASE 0 -#define JOYDEV_MINORS 16 +#define JOYDEV_MINORS 16 #define JOYDEV_BUFFER_SIZE 64 #define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) @@ -115,7 +115,7 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne default: return; - } + } event.time = MSECS(jiffies); @@ -449,10 +449,10 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct } joydev_table[minor] = joydev; - + devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); - class_simple_device_add(input_class, + class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), dev->dev, "js%d", minor); @@ -466,7 +466,7 @@ static void joydev_disconnect(struct input_handle *handle) joydev->exist = 0; if (joydev->open) - input_close_device(handle); + input_close_device(handle); else joydev_free(joydev); } diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 1ae033888..7d506f1f7 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -22,7 +22,7 @@ config JOYSTICK_ANALOG supports many extensions, including joysticks with throttle control, with rudders, additional hats and buttons compatible with CH Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or - Saitek Cyborg joysticks. + Saitek Cyborg joysticks. Please read the file which contains more information. @@ -35,7 +35,7 @@ config JOYSTICK_A3D depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you have an FPGaming or MadCatz controller using the - A3D protocol over the PC gameport. + A3D protocol over the PC gameport. To compile this driver as a module, choose M here: the module will be called a3d. @@ -45,7 +45,7 @@ config JOYSTICK_ADI depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you have a Logitech controller using the ADI - protocol over the PC gameport. + protocol over the PC gameport. To compile this driver as a module, choose M here: the module will be called adi. @@ -74,7 +74,7 @@ config JOYSTICK_GRIP depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you have a Gravis controller using the GrIP protocol - over the PC gameport. + over the PC gameport. To compile this driver as a module, choose M here: the module will be called grip. @@ -94,7 +94,7 @@ config JOYSTICK_GUILLEMOT depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you have a Guillemot joystick using a digital - protocol over the PC gameport. + protocol over the PC gameport. To compile this driver as a module, choose M here: the module will be called guillemot. @@ -124,7 +124,7 @@ config JOYSTICK_TMDC depends on INPUT && INPUT_JOYSTICK && GAMEPORT help Say Y here if you have a ThrustMaster controller using the - DirectConnect (BSP) protocol over the PC gameport. + DirectConnect (BSP) protocol over the PC gameport. To compile this driver as a module, choose M here: the module will be called tmdc. @@ -137,7 +137,7 @@ config JOYSTICK_WARRIOR select SERIO help Say Y here if you have a Logitech WingMan Warrior joystick connected - to your computer's serial port. + to your computer's serial port. To compile this driver as a module, choose M here: the module will be called warrior. @@ -253,7 +253,7 @@ config INPUT_JOYDUMP help Say Y here if you want to dump data from your joystick into the system log for debugging purposes. Say N if you are making a production - configuration or aren't sure. + configuration or aren't sure. To compile this driver as a module, choose M here: the module will be called joydump. diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 9d66a654e..b3eb64fdc 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -39,8 +39,8 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver"); MODULE_LICENSE("GPL"); -#define A3D_MAX_START 400 /* 400 us */ -#define A3D_MAX_STROBE 60 /* 40 us */ +#define A3D_MAX_START 400 /* 400 us */ +#define A3D_MAX_STROBE 60 /* 40 us */ #define A3D_DELAY_READ 3 /* 3 ms */ #define A3D_MAX_LENGTH 40 /* 40*3 bits */ #define A3D_REFRESH_TIME HZ/50 /* 20 ms */ @@ -125,7 +125,7 @@ static void a3d_read(struct a3d *a3d, unsigned char *data) input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7)); input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7)); - + input_report_key(dev, BTN_RIGHT, data[2] & 1); input_report_key(dev, BTN_LEFT, data[3] & 2); input_report_key(dev, BTN_MIDDLE, data[3] & 4); @@ -201,7 +201,7 @@ int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) int i; for (i = 0; i < 4; i++) axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; - *buttons = a3d->buttons; + *buttons = a3d->buttons; return 0; } @@ -216,7 +216,7 @@ int a3d_adc_open(struct gameport *gameport, int mode) if (mode != GAMEPORT_MODE_COOKED) return -1; if (!a3d->used++) - mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); + mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); return 0; } @@ -239,7 +239,7 @@ static int a3d_open(struct input_dev *dev) { struct a3d *a3d = dev->private; if (!a3d->used++) - mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); + mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME); return 0; } @@ -340,7 +340,7 @@ static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) a3d->adc.open = a3d_adc_open; a3d->adc.close = a3d_adc_close; a3d->adc.cooked_read = a3d_adc_cooked_read; - a3d->adc.fuzz = 1; + a3d->adc.fuzz = 1; a3d->adc.name = a3d_names[a3d->mode]; a3d->adc.phys = a3d->adcphys; diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index df57287cc..8b5fc358d 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -46,7 +46,7 @@ MODULE_DESCRIPTION("Driver for Amiga joysticks"); MODULE_LICENSE("GPL"); static int amijoy[2] = { 0, 1 }; -static int amijoy_nargs; +static int amijoy_nargs; module_param_array_named(map, amijoy, uint, amijoy_nargs, 0); MODULE_PARM_DESC(map, "Map of attached joysticks in form of , (default is 0,1)"); diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 9ca36edd1..fc29ad79b 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -72,7 +72,7 @@ static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int * r[i] = buf[i] = 0; t[i] = COBRA_MAX_STROBE; } - + local_irq_save(flags); u = gameport_read(gameport); @@ -140,14 +140,14 @@ static void cobra_timer(unsigned long private) } - mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); + mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); } static int cobra_open(struct input_dev *dev) { struct cobra *cobra = dev->private; if (!cobra->used++) - mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); + mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); return 0; } @@ -180,7 +180,7 @@ static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev) cobra->exists = cobra_read_packet(gameport, data); - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) if ((cobra->exists >> i) & data[i] & 1) { printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); @@ -205,7 +205,7 @@ static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev) cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; cobra->dev[i].id.product = 0x0008; cobra->dev[i].id.version = 0x0100; - + cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index f7d3eebd7..5ad612751 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -14,14 +14,14 @@ /* * 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 + * 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 @@ -95,7 +95,7 @@ __obsolete_setup("db9_3="); struct db9 { struct input_dev dev[DB9_MAX_DEVICES]; struct timer_list timer; - struct pardevice *pd; + struct pardevice *pd; int mode; int used; char phys[2][32]; @@ -188,7 +188,7 @@ static unsigned char db9_saturn_read_analog(struct parport *port, int type, int } /* - * db9_saturn_read_packet() reads whole saturn packet at connector + * db9_saturn_read_packet() reads whole saturn packet at connector * and returns device identifier code. */ static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered) @@ -481,16 +481,16 @@ static void db9_timer(unsigned long private) input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); - parport_write_control(port, 0x0a); + parport_write_control(port, 0x0a); - for (i = 0; i < 7; i++) { + for (i = 0; i < 7; i++) { data = parport_read_data(port); - parport_write_control(port, 0x02); - parport_write_control(port, 0x0a); + parport_write_control(port, 0x02); + parport_write_control(port, 0x0a); input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); } - parport_write_control(port, 0x00); + parport_write_control(port, 0x00); break; } @@ -600,7 +600,7 @@ static struct db9 __init *db9_probe(int *config, int nargs) db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (j = 0; j < db9_buttons[db9->mode]; j++) - set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); + set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); for (j = 0; j < db9_num_axis[db9->mode]; j++) { set_bit(db9_abs[j], db9->dev[i].absbit); if (j < 2) { @@ -635,7 +635,7 @@ void __exit db9_exit(void) { int i, j; - for (i = 0; i < 3; i++) + for (i = 0; i < 3; i++) if (db9_base[i]) { for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++) input_unregister_device(db9_base[i]->dev + j); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 02ee05a98..555fb362b 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -15,14 +15,14 @@ /* * 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 + * 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 @@ -70,13 +70,13 @@ __obsolete_setup("gc_3="); #define GC_NES4 3 #define GC_MULTI 4 #define GC_MULTI2 5 -#define GC_N64 6 +#define GC_N64 6 #define GC_PSX 7 #define GC_MAX 7 #define GC_REFRESH_TIME HZ/100 - + struct gc { struct pardevice *pd; struct input_dev dev[5]; @@ -104,7 +104,7 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, #define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ #define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */ #define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ - /* GC_N64_DWS > 24 is known to fail */ + /* GC_N64_DWS > 24 is known to fail */ #define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */ #define GC_N64_POWER_R 0xfd /* power during read */ #define GC_N64_OUT 0x1d /* output bits to the 4 pads */ @@ -113,8 +113,8 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, /* than 123 us */ #define GC_N64_CLOCK 0x02 /* clock bits for read */ -/* - * gc_n64_read_packet() reads an N64 packet. +/* + * gc_n64_read_packet() reads an N64 packet. * Each pad uses one bit per byte. So all pads connected to this port are read in parallel. */ @@ -224,7 +224,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt * http://www.gamesx.com/controldata/psxcont/psxcont.htm * ftp://milano.usal.es/pablo/ - * + * */ #define GC_PSX_DELAY 25 /* 25 usec */ @@ -331,13 +331,13 @@ static void gc_timer(unsigned long private) s = gc_status_bit[i]; if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) { - + signed char axes[2]; axes[0] = axes[1] = 0; for (j = 0; j < 8; j++) { - if (data[23 - j] & s) axes[0] |= 1 << j; - if (data[31 - j] & s) axes[1] |= 1 << j; + if (data[23 - j] & s) axes[0] |= 1 << j; + if (data[31 - j] & s) axes[1] |= 1 << j; } input_report_abs(dev + i, ABS_X, axes[0]); @@ -588,7 +588,7 @@ static struct gc __init *gc_probe(int *config, int nargs) break; case GC_PSX: - + psx = gc_psx_read_packet(gc, data); switch(psx) { @@ -629,7 +629,7 @@ static struct gc __init *gc_probe(int *config, int nargs) } sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); - + gc->dev[i].name = gc_names[config[i + 1]]; gc->dev[i].phys = gc->phys[i]; gc->dev[i].id.bustype = BUS_PARPORT; @@ -646,7 +646,7 @@ static struct gc __init *gc_probe(int *config, int nargs) return NULL; } - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) if (gc->pads[0] & gc_status_bit[i]) { input_register_device(gc->dev + i); printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); @@ -675,7 +675,7 @@ void __exit gc_exit(void) if (gc_base[i]) { for (j = 0; j < 5; j++) if (gc_base[i]->pads[0] & gc_status_bit[j]) - input_unregister_device(gc_base[i]->dev + j); + input_unregister_device(gc_base[i]->dev + j); parport_unregister_device(gc_base[i]->pd); } } diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index 9acf65af4..3b1b07e2d 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -48,8 +48,8 @@ MODULE_LICENSE("GPL"); #define GRIP_STROBE_GPP 200 /* 200 us */ #define GRIP_LENGTH_XT 4 #define GRIP_STROBE_XT 64 /* 64 us */ -#define GRIP_MAX_CHUNKS_XT 10 -#define GRIP_MAX_BITS_XT 30 +#define GRIP_MAX_CHUNKS_XT 10 +#define GRIP_MAX_BITS_XT 30 #define GRIP_REFRESH_TIME HZ/50 /* 20 ms */ @@ -153,7 +153,7 @@ static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned in buf = (buf << 1) | (u >> 1); t = strobe; i++; - } else + } else if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { if (i == 20) { diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index d7623485f..995caa3e4 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -69,7 +69,7 @@ struct grip_mp { #define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ #define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ #define IO_DONE 0x1000 /* Multiport is done sending packets */ -#define IO_RETRY 0x4000 /* Try again later to get packet */ +#define IO_RETRY 0x4000 /* Try again later to get packet */ #define IO_RESET 0x8000 /* Force multiport to resend all packets */ /* @@ -144,8 +144,8 @@ static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* /* * Gets a 28-bit packet from the multiport. * - * After getting a packet successfully, commands encoded by sendcode may - * be sent to the multiport. + * After getting a packet successfully, commands encoded by sendcode may + * be sent to the multiport. * * The multiport clock value is reflected in gameport bit B4. * @@ -169,7 +169,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa *packet = 0; raw_data = gameport_read(gameport); - if (raw_data & 1) + if (raw_data & 1) return IO_RETRY; for (i = 0; i < 64; i++) { @@ -183,11 +183,11 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa if (raw_data & 0x31) return IO_RESET; - gameport_trigger(gameport); + gameport_trigger(gameport); if (!poll_until(0x10, 0, 308, gameport, &raw_data)) return IO_RESET; - } else + } else return IO_RETRY; /* Determine packet transfer mode and prepare for packet construction. */ @@ -195,7 +195,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa if (raw_data & 0x20) { /* 3 data bits/read */ portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ - if (portvals != 0xb) + if (portvals != 0xb) return 0; data_mask = 7; bits_per_read = 3; @@ -221,7 +221,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa return IO_RESET; } - if (raw_data) + if (raw_data) return IO_RESET; /* If 3 bits/read used, drop from 30 bits to 28. */ @@ -231,7 +231,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa pkt = (pkt >> 2) | 0xf0000000; } - if (bit_parity(pkt) == 1) + if (bit_parity(pkt) == 1) return IO_RESET; /* Acknowledge packet receipt */ @@ -251,10 +251,10 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa /* Return if we just wanted the packet or multiport wants to send more */ - *packet = pkt; + *packet = pkt; if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) return IO_GOT_PACKET; - + if (pkt & PACKET_MP_MORE) return IO_GOT_PACKET | IO_RETRY; @@ -277,7 +277,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa if (!poll_until(0x30, 0, 193, gameport, &raw_data)) return IO_GOT_PACKET | IO_RESET; - if (raw_data & 1) + if (raw_data & 1) return IO_GOT_PACKET | IO_RESET; if (sendcode & 1) @@ -429,19 +429,19 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) strange_code = joytype; } } - return flags; + return flags; } /* * Returns true if all multiport slot states appear valid. */ - + static int slots_valid(struct grip_mp *grip) { int flags, slot, invalid = 0, active = 0; flags = get_and_decode_packet(grip, 0); - if (!(flags & IO_GOT_PACKET)) + if (!(flags & IO_GOT_PACKET)) return 0; for (slot = 0; slot < 4; slot++) { @@ -463,7 +463,7 @@ static int slots_valid(struct grip_mp *grip) * Returns whether the multiport was placed into digital mode and * able to communicate its state successfully. */ - + static int multiport_init(struct grip_mp *grip) { int dig_mode, initialized = 0, tries = 0; @@ -481,7 +481,7 @@ static int multiport_init(struct grip_mp *grip) dbg("multiport_init(): unable to achieve digital mode.\n"); return 0; } - + /* Get packets, store multiport state, and check state's validity */ for (tries = 0; tries < 4096; tries++) { if ( slots_valid(grip) ) { @@ -520,9 +520,9 @@ static void report_slot(struct grip_mp *grip, int slot) } /* - * Get the multiport state. + * Get the multiport state. */ - + static void get_and_report_mp_state(struct grip_mp *grip) { int i, npkts, flags; @@ -538,7 +538,7 @@ static void get_and_report_mp_state(struct grip_mp *grip) break; } - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) if (grip->dirty[i]) report_slot(grip, i); } @@ -546,7 +546,7 @@ static void get_and_report_mp_state(struct grip_mp *grip) /* * Called when a joystick device file is opened */ - + static int grip_open(struct input_dev *dev) { struct grip_mp *grip = dev->private; @@ -607,7 +607,7 @@ static void register_slot(int slot, struct grip_mp *grip) /* * Repeatedly polls the multiport and generates events. */ - + static void grip_timer(unsigned long private) { struct grip_mp *grip = (void*) private; diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 456e19983..cfe8c6be1 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -45,7 +45,7 @@ MODULE_LICENSE("GPL"); #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ #define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */ -static short guillemot_abs_pad[] = +static short guillemot_abs_pad[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; static short guillemot_btn_pad[] = @@ -160,7 +160,7 @@ static int guillemot_open(struct input_dev *dev) { struct guillemot *guillemot = dev->private; if (!guillemot->used++) - mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); return 0; } @@ -211,7 +211,7 @@ static void guillemot_connect(struct gameport *gameport, struct gameport_dev *de if (!guillemot_type[i].name) { printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", gameport->phys, data[12], data[13], data[11], data[14], data[15]); - goto fail2; + goto fail2; } sprintf(guillemot->phys, "%s/input0", gameport->phys); @@ -237,7 +237,7 @@ static void guillemot_connect(struct gameport *gameport, struct gameport_dev *de guillemot->dev.absmax[t] = 255; } - if (guillemot->type->hat) + if (guillemot->type->hat) for (i = 0; i < 2; i++) { t = ABS_HAT0X + i; set_bit(t, guillemot->dev.absbit); diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig index 8b0195748..2e964e5f5 100644 --- a/drivers/input/joystick/iforce/Kconfig +++ b/drivers/input/joystick/iforce/Kconfig @@ -17,7 +17,7 @@ config JOYSTICK_IFORCE_USB depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB help Say Y here if you have an I-Force joystick or steering wheel - connected to your USB port. + connected to your USB port. config JOYSTICK_IFORCE_232 bool "I-Force Serial joysticks and wheels" diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile index 96a077172..17ae42bf9 100644 --- a/drivers/input/joystick/iforce/Makefile +++ b/drivers/input/joystick/iforce/Makefile @@ -7,14 +7,14 @@ # Goal definition iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) - iforce-objs += iforce-serio.o + iforce-objs += iforce-serio.o endif ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) - iforce-objs += iforce-usb.o + iforce-objs += iforce-usb.o endif EXTRA_CFLAGS = -Werror-implicit-function-declaration diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 267f92f0a..4678b6dab 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -195,7 +195,7 @@ static unsigned char find_button(struct iforce *iforce, signed short button) } /* - * Analyse the changes in an effect, and tell if we need to send an condition + * Analyse the changes in an effect, and tell if we need to send an condition * parameter packet */ static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) @@ -372,7 +372,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int int core_err = 0; if (!is_update || need_period_modifier(iforce, effect)) { - param1_err = make_period_modifier(iforce, mod1_chunk, + param1_err = make_period_modifier(iforce, mod1_chunk, is_update, effect->u.periodic.magnitude, effect->u.periodic.offset, effect->u.periodic.period, effect->u.periodic.phase); diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index c53e61acb..71cb7db75 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -166,7 +166,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) else { /* We want to update an effect */ if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; - + /* Parameter type cannot be updated */ if (effect->type != iforce->core_effects[effect->id].effect.type) return -EINVAL; @@ -273,7 +273,7 @@ static int iforce_flush(struct input_dev *dev, struct file *file) if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && current->pid == iforce->core_effects[i].owner) { - + /* Stop effect */ input_report_ff(dev, i, 0); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 0c37044ef..58728ebaa 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -56,7 +56,7 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) int empty; int head, tail; unsigned long flags; - + /* * Update head and tail of xmit buffer */ @@ -108,7 +108,7 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) break; #endif #ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: + case IFORCE_USB: if (iforce->usbdev && empty && !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index e17c2e8a5..0665b5460 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -62,7 +62,7 @@ again: cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); } - + serio_write(iforce->serio, cs); if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 5b902522e..a8586abf5 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -141,7 +141,7 @@ struct iforce { struct circ_buf xmit; unsigned char xmit_data[XMIT_SIZE]; long xmit_flags[1]; - + /* Force Feedback */ wait_queue_head_t wait; struct resource device_memory; diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index adc20ac50..b2d7cad81 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -63,7 +63,7 @@ struct interact { char phys[32]; }; -static short interact_abs_hhfx[] = +static short interact_abs_hhfx[] = { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; static short interact_abs_pp8d[] = { ABS_X, ABS_Y, -1 }; @@ -166,7 +166,7 @@ static void interact_timer(unsigned long private) case INTERACT_TYPE_PP8D: for (i = 0; i < 2; i++) - input_report_abs(dev, interact_abs_pp8d[i], + input_report_abs(dev, interact_abs_pp8d[i], ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); for (i = 0; i < 8; i++) @@ -190,7 +190,7 @@ static int interact_open(struct input_dev *dev) { struct interact *interact = dev->private; if (!interact->used++) - mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); + mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); return 0; } @@ -242,7 +242,7 @@ static void interact_connect(struct gameport *gameport, struct gameport_dev *dev if (!interact_type[i].length) { printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", gameport->phys, i, data[0], data[1], data[2]); - goto fail2; + goto fail2; } sprintf(interact->phys, "%s/input0", gameport->phys); diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index 9f3bed21b..15962a684 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -12,18 +12,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -63,7 +63,7 @@ static void __devinit joydump_connect(struct gameport *gameport, struct gameport printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) { - + printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); return; diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 992511d83..f326299b4 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -159,7 +159,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) memset(magellan, 0, sizeof(struct magellan)); - magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < 9; i++) set_bit(magellan_buttons[i], magellan->dev.keybit); @@ -181,7 +181,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) magellan->dev.id.vendor = SERIO_MAGELLAN; magellan->dev.id.product = 0x0001; magellan->dev.id.version = 0x0100; - + serio->private = magellan; if (serio_open(serio, dev)) { diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index af8263e02..084643d58 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -176,19 +176,19 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len buf[i] = v >> 5; /* Store it */ i++; /* Advance index */ bitout = strobe; /* Extend timeout for next bit */ - } + } if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ sched = kick; /* Schedule second trigger */ kick = 0; /* Don't schedule next time on falling edge */ pending = 1; /* Mark schedule */ - } + } if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */ gameport_trigger(gameport); /* Trigger */ bitout = start; /* Long bit timeout */ pending = 0; /* Unmark schedule */ - timeout = 0; /* Switch from global to bit timeouts */ + timeout = 0; /* Switch from global to bit timeouts */ } } @@ -482,14 +482,14 @@ static int sw_read(struct sw *sw) sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ sw->fail = SW_FAIL; - + return -1; } static void sw_timer(unsigned long private) { struct sw *sw = (void *) private; - + sw->reads++; if (sw_read(sw)) sw->bads++; mod_timer(&sw->timer, jiffies + SW_REFRESH); @@ -653,7 +653,7 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev) case 60: sw->number++; case 45: /* Ambiguous packet length */ - if (j <= 40) { /* ID length less or eq 40 -> FSP */ + if (j <= 40) { /* ID length less or eq 40 -> FSP */ case 43: sw->type = SW_ID_FSP; break; diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 4e288b58c..eb5b6f76c 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -15,18 +15,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -59,8 +59,8 @@ MODULE_LICENSE("GPL"); static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; static char *spaceball_names[] = { - "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", - "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", + "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", + "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", "SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" }; /* @@ -96,7 +96,7 @@ static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs case 'D': /* Ball data */ if (spaceball->idx != 15) return; for (i = 0; i < 6; i++) - input_report_abs(dev, spaceball_axes[i], + input_report_abs(dev, spaceball_axes[i], (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); break; @@ -216,7 +216,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) return; memset(spaceball, 0, sizeof(struct spaceball)); - spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); switch (id) { case SPACEBALL_4000FLX: @@ -224,7 +224,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); default: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) + spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); case SPACEBALL_3003C: spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); @@ -251,7 +251,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) spaceball->dev.id.vendor = SERIO_SPACEBALL; spaceball->dev.id.product = id; spaceball->dev.id.version = 0x0100; - + serio->private = spaceball; if (serio_open(serio, dev)) { diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 593dcac96..00da66c4b 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -2,7 +2,7 @@ * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik - * + * * Based on the work of: * David Thompson */ @@ -14,18 +14,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -67,7 +67,7 @@ struct spaceorb { static unsigned char spaceorb_xor[] = "SpaceWare"; static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", - "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; + "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; /* * spaceorb_process_packet() decodes packets the driver receives from the @@ -99,7 +99,7 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r case 'D': /* Ball + button data */ if (spaceorb->idx != 12) return; - for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; + for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; axes[0] = ( data[2] << 3) | (data[ 3] >> 4); axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); @@ -174,7 +174,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) return; memset(spaceorb, 0, sizeof(struct spaceorb)); - spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < 6; i++) set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); @@ -198,7 +198,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) spaceorb->dev.id.vendor = SERIO_SPACEORB; spaceorb->dev.id.product = 0x0001; spaceorb->dev.id.version = 0x0100; - + serio->private = spaceorb; if (serio_open(serio, dev)) { diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index f68d3add2..ce9be4563 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -147,7 +147,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) memset(stinger, 0, sizeof(struct stinger)); - stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ BIT(BTN_START) | BIT(BTN_SELECT); @@ -164,8 +164,8 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) stinger->dev.id.version = 0x0100; for (i = 0; i < 2; i++) { - stinger->dev.absmax[ABS_X+i] = 64; - stinger->dev.absmin[ABS_X+i] = -64; + stinger->dev.absmax[ABS_X+i] = 64; + stinger->dev.absmin[ABS_X+i] = -64; stinger->dev.absflat[ABS_X+i] = 4; } diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 93efe7520..6ed46ec46 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -4,7 +4,7 @@ * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: - * Trystan Larey-Williams + * Trystan Larey-Williams */ /* @@ -14,18 +14,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -58,7 +58,7 @@ MODULE_LICENSE("GPL"); #define TMDC_BYTE_REV 11 #define TMDC_BYTE_DEF 12 -#define TMDC_ABS 7 +#define TMDC_ABS 7 #define TMDC_ABS_HAT 4 #define TMDC_BTN 16 @@ -104,7 +104,7 @@ struct tmdc { unsigned char btno[2][4]; int used; int reads; - int bads; + int bads; unsigned char exists; }; @@ -127,7 +127,7 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD local_irq_save(flags); gameport_trigger(gameport); - + w = gameport_read(gameport) >> 4; do { @@ -148,7 +148,7 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD } data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ } - t[k]--; + t[k]--; } } while (t[0] > 0 || t[1] > 0); @@ -175,7 +175,7 @@ static void tmdc_timer(unsigned long private) bad = 1; else - for (j = 0; j < 2; j++) + for (j = 0; j < 2; j++) if (r & (1 << j) & tmdc->exists) { if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { @@ -227,7 +227,7 @@ static int tmdc_open(struct input_dev *dev) { struct tmdc *tmdc = dev->private; if (!tmdc->used++) - mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); + mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); return 0; } @@ -356,7 +356,7 @@ static void tmdc_disconnect(struct gameport *gameport) struct tmdc *tmdc = gameport->private; int i; for (i = 0; i < 2; i++) - if (tmdc->exists & (1 << i)) + if (tmdc->exists & (1 << i)) input_unregister_device(tmdc->dev + i); gameport_close(gameport); kfree(tmdc); diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 8cf86aa83..123ff5f9d 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -14,18 +14,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -65,7 +65,7 @@ __obsolete_setup("tgfx_3="); #define TGFX_TRIGGER 0x08 #define TGFX_UP 0x10 -#define TGFX_DOWN 0x20 +#define TGFX_DOWN 0x20 #define TGFX_LEFT 0x40 #define TGFX_RIGHT 0x80 @@ -126,7 +126,7 @@ static int tgfx_open(struct input_dev *dev) if (!tgfx->used++) { parport_claim(tgfx->pd); parport_write_control(tgfx->pd->port, 0x04); - mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); + mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); } return 0; } @@ -173,7 +173,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs) memset(tgfx, 0, sizeof(struct tgfx)); tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - + parport_put_port(pp); if (!tgfx->pd) { @@ -210,7 +210,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs) tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); for (j = 0; j < config[i+1]; j++) - set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); + set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; @@ -225,7 +225,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs) kfree(tgfx); return NULL; } - + return tgfx; } @@ -245,7 +245,7 @@ void __exit tgfx_exit(void) { int i, j; - for (i = 0; i < 3; i++) + for (i = 0; i < 3; i++) if (tgfx_base[i]) { for (j = 0; j < 7; j++) if (tgfx_base[i]->sticks & (1 << j)) diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 8a98be150..eb5c935a6 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -58,6 +58,9 @@ #include #include +MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver"); +MODULE_LICENSE("GPL"); + /* * Constants. */ @@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs * packet processing routine. */ -static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struc pt_regs *regs) +static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) { struct twidjoy *twidjoy = serio->private; @@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned if ((data & 0x80) == 0) twidjoy->idx = 0; /* this byte starts a new packet */ else if (twidjoy->idx == 0) - return; /* wrong MSB -- ignore this byte */ + return IRQ_HANDLED; /* wrong MSB -- ignore this byte */ if (twidjoy->idx < TWIDJOY_MAX_LENGTH) twidjoy->data[twidjoy->idx++] = data; @@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned twidjoy->idx = 0; } - return; + return IRQ_HANDLED; } /* @@ -208,7 +211,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) twidjoy->dev.id.product = 0x0001; twidjoy->dev.id.version = 0x0100; - twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (bp = twidjoy_buttons; bp->bitmask; bp++) { for (i = 0; i < bp->bitmask; i++) @@ -218,8 +221,8 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); for (i = 0; i < 2; i++) { - twidjoy->dev.absmax[ABS_X+i] = 50; - twidjoy->dev.absmin[ABS_X+i] = -50; + twidjoy->dev.absmax[ABS_X+i] = 50; + twidjoy->dev.absmin[ABS_X+i] = -50; /* TODO: arndt 20010708: Are these values appropriate? */ twidjoy->dev.absfuzz[ABS_X+i] = 4; diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 426ce2d5e..32ec90e81 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -11,18 +11,18 @@ /* * This program is free warftware; 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -44,7 +44,7 @@ MODULE_LICENSE("GPL"); */ #define WARRIOR_MAX_LENGTH 16 -static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; +static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; static char *warrior_name = "Logitech WingMan Warrior"; /* @@ -114,7 +114,7 @@ static irqreturn_t warrior_interrupt(struct serio *serio, warrior->data[warrior->idx++] = data; if (warrior->idx == warrior->len) { - if (warrior->idx) warrior_process_packet(warrior, regs); + if (warrior->idx) warrior_process_packet(warrior, regs); warrior->idx = 0; warrior->len = 0; } @@ -152,7 +152,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) memset(warrior, 0, sizeof(struct warrior)); - warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); warrior->dev.relbit[0] = BIT(REL_DIAL); warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); @@ -168,24 +168,24 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) warrior->dev.id.version = 0x0100; for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_X+i] = -64; - warrior->dev.absmin[ABS_X+i] = 64; - warrior->dev.absflat[ABS_X+i] = 8; + warrior->dev.absmax[ABS_X+i] = -64; + warrior->dev.absmin[ABS_X+i] = 64; + warrior->dev.absflat[ABS_X+i] = 8; } - warrior->dev.absmax[ABS_THROTTLE] = -112; - warrior->dev.absmin[ABS_THROTTLE] = 112; + warrior->dev.absmax[ABS_THROTTLE] = -112; + warrior->dev.absmin[ABS_THROTTLE] = 112; for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_HAT0X+i] = -1; - warrior->dev.absmin[ABS_HAT0X+i] = 1; + warrior->dev.absmax[ABS_HAT0X+i] = -1; + warrior->dev.absmin[ABS_HAT0X+i] = 1; } warrior->dev.private = warrior; - + serio->private = warrior; - if (serio_open(serio, dev)) { + if (serio_open(serio, dev)) { kfree(warrior); return; } diff --git a/drivers/input/keyboard/98kbd.c b/drivers/input/keyboard/98kbd.c index 803df0db0..970a5ae1a 100644 --- a/drivers/input/keyboard/98kbd.c +++ b/drivers/input/keyboard/98kbd.c @@ -12,18 +12,18 @@ /* * 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 + * 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 @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); #define KBD98_KEY 0x7f #define KBD98_RELEASE 0x80 -static unsigned char kbd98_keycode[256] = { +static unsigned char kbd98_keycode[256] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 41, 26, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 27, 44, 45, 46, 47, 48, 49, 50, @@ -109,8 +109,8 @@ struct kbd98 { struct jis_kbd_conv jis[16]; }; -void kbd98_interrupt(struct serio *serio, unsigned char data, - unsigned int flags, struct pt_regs *regs) +irqreturn_t kbd98_interrupt(struct serio *serio, unsigned char data, + unsigned int flags, struct pt_regs *regs) { struct kbd98 *kbd98 = serio->private; unsigned char scancode, keycode; @@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, switch (data) { case KBD98_RET_ACK: kbd98->ack = 1; - return; + goto out; case KBD98_RET_NAK: kbd98->ack = -1; - return; + goto out; } if (kbd98->cmdcnt) { kbd98->cmdbuf[--kbd98->cmdcnt] = data; - return; + goto out; } scancode = data & KBD98_KEY; @@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, keycode = kbd98->jis[i].emul[kbd98->shift].keycode; if (keycode == KBD98_KEY_NULL) - return; + break; if (press) { kbd98->emul.scancode = scancode; @@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, } input_sync(&kbd98->dev); - return; + break; case KEY_CAPSLOCK: input_report_key(&kbd98->dev, keycode, 1); input_sync(&kbd98->dev); input_report_key(&kbd98->dev, keycode, 0); input_sync(&kbd98->dev); - return; + break; case KBD98_KEY_NULL: - return; + break; case 0: printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n", data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed"); - return; + break; default: input_report_key(&kbd98->dev, keycode, press); input_sync(&kbd98->dev); - } + break; + } + +out: + return IRQ_HANDLED; } /* @@ -243,7 +247,7 @@ static int kbd98_command(struct kbd98 *kbd98, unsigned char *param, int command) int i; kbd98->cmdcnt = receive; - + if (command & 0xff) if (kbd98_sendbyte(kbd98, command & 0xff)) return (kbd98->cmdcnt = 0) - 1; @@ -258,7 +262,7 @@ static int kbd98_command(struct kbd98 *kbd98, unsigned char *param, int command) for (i = 0; i < receive; i++) param[i] = kbd98->cmdbuf[(receive - 1) - i]; - if (kbd98->cmdcnt) + if (kbd98->cmdcnt) return (kbd98->cmdcnt = 0) - 1; return 0; @@ -318,7 +322,7 @@ void kbd98_connect(struct serio *serio, struct serio_dev *dev) memset(kbd98, 0, sizeof(struct kbd98)); kbd98->emul.scancode = KBD98_KEY_UNKNOWN; - + kbd98->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); kbd98->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_KANA); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 36d32820d..45322b41a 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -62,7 +62,7 @@ config KEYBOARD_XTKBD Say Y here if you want to use the old IBM PC/XT keyboard (or compatible) on your system. This is only possible with a parallel port keyboard adapter, you cannot connect it to the - keyboard port on a PC that runs Linux. + keyboard port on a PC that runs Linux. To compile this driver as a module, choose M here: the module will be called xtkbd. @@ -92,7 +92,7 @@ config KEYBOARD_AMIGA depends on AMIGA && INPUT && INPUT_KEYBOARD help Say Y here if you are running Linux on any AMIGA and have a keyboard - attached. + attached. To compile this driver as a module, choose M here: the module will be called amikbd. @@ -103,7 +103,7 @@ config KEYBOARD_98KBD select SERIO help Say Y here if you want to use the NEC PC-9801/PC-9821 keyboard (or - compatible) on your system. + compatible) on your system. To compile this driver as a module, choose M here: the module will be called 98kbd. diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 871440418..026fc13ea 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -26,7 +26,6 @@ #include #include #include -#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); @@ -173,22 +172,24 @@ struct atkbd { unsigned char keycode[512]; struct input_dev dev; struct serio *serio; - struct timer_list timer; + char name[64]; char phys[32]; + unsigned short id; + unsigned char set; + unsigned int translated:1; + unsigned int extra:1; + unsigned int write:1; + unsigned char cmdbuf[4]; unsigned char cmdcnt; - unsigned char set; - unsigned char extra; - unsigned char release; - int lastkey; volatile signed char ack; unsigned char emul; - unsigned short id; - unsigned char write; - unsigned char translated; - unsigned char resend; - unsigned char bat_xl; + unsigned int resend:1; + unsigned int release:1; + unsigned int bat_xl:1; + unsigned int enabled:1; + unsigned int last; unsigned long time; }; @@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, goto out; } + if (!atkbd->enabled) + goto out; + if (atkbd->translated) { if (atkbd->emul || @@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, case ATKBD_KEY_NULL: break; case ATKBD_KEY_UNKNOWN: - printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", - atkbd->release ? "released" : "pressed", - atkbd->translated ? "translated" : "raw", - atkbd->set, code, serio->phys); - if (atkbd->translated && atkbd->set == 2 && code == 0x7a) - printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access" - " hardware directly.\n"); - else - printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x ' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); + if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { + printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " + "like XFree86, might be trying access hardware directly.\n", + data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); + } else { + printk(KERN_WARNING "atkbd.c: Unknown key %s " + "(%s set %d, code %#x on %s).\n", + atkbd->release ? "released" : "pressed", + atkbd->translated ? "translated" : "raw", + atkbd->set, code, serio->phys); + printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x ' " + "to make it known.\n", + code & 0x80 ? "e0" : "", code & 0x7f); + } break; case ATKBD_SCR_1: scroll = 1 - atkbd->release * 2; @@ -745,6 +754,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) atkbd->id = 0xab00; } + atkbd->enabled = 1; + if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); sprintf(atkbd->name, "AT Set 2 Extra keyboard"); @@ -809,12 +820,12 @@ static int atkbd_reconnect(struct serio *serio) param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); - + if (atkbd_probe(atkbd)) return -1; if (atkbd->set != atkbd_set_3(atkbd)) return -1; - + atkbd_enable(atkbd); if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index eb5fe4d83..859ed771e 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -139,7 +139,7 @@ static int dc_kbd_connect(struct maple_device *dev) kbd->dev.name = dev->product_name; kbd->dev.id.bustype = BUS_MAPLE; - + input_register_device(&kbd->dev); maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index d2f70364a..1bb8a57e2 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -148,7 +148,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c case EV_LED: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, + sunkbd->serio->write(sunkbd->serio, (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); return 0; @@ -160,7 +160,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c case SND_CLICK: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); return 0; - + case SND_BELL: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); return 0; @@ -210,7 +210,7 @@ static void sunkbd_reinit(void *data) wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, + sunkbd->serio->write(sunkbd->serio, (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); @@ -231,7 +231,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD) return; - + if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) return; diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 78847c60f..56adfa1cc 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); #define XTKBD_KEY 0x7f #define XTKBD_RELEASE 0x80 -static unsigned char xtkbd_keycode[256] = { +static unsigned char xtkbd_keycode[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, @@ -98,7 +98,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev) return; memset(xtkbd, 0, sizeof(struct xtkbd)); - + xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); xtkbd->serio = serio; diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 6c5c08ded..6d793addf 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -53,11 +53,11 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in case SND_BELL: if (value) value = 1000; case SND_TONE: break; default: return -1; - } + } if (value > 20 && value < 32767) count = 1193182 / value; - + spin_lock_irqsave(&beep_lock, flags); /* EBUS speaker only has on/off state, the frequency does not @@ -108,11 +108,11 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int case SND_BELL: if (value) value = 1000; case SND_TONE: break; default: return -1; - } + } if (value > 20 && value < 32767) count = 1193182 / value; - + spin_lock_irqsave(&beep_lock, flags); if (count) { diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index cc8c05b59..2e097dc66 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Aristeu Sergio Rozanski Filho - * + * * Changes/Revisions: * 0.1 20/06/2002 * - first public version @@ -68,7 +68,7 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) { return 0; -} +} static int uinput_create_device(struct uinput_device *udev) { @@ -123,7 +123,7 @@ static int uinput_open(struct inode *inode, struct file *file) memset(newinput, 0, sizeof(struct input_dev)); newdev->dev = newinput; - + file->private_data = newdev; return 0; @@ -137,16 +137,16 @@ static int uinput_validate_absbits(struct input_dev *dev) { unsigned int cnt; int retval = 0; - + for (cnt = 0; cnt < ABS_MAX; cnt++) { - if (!test_bit(cnt, dev->absbit)) + if (!test_bit(cnt, dev->absbit)) continue; - + if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */ (dev->absmax[cnt] <= dev->absmin[cnt])) { - printk(KERN_DEBUG + printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n", - UINPUT_NAME, cnt, + UINPUT_NAME, cnt, dev->absmin[cnt], dev->absmax[cnt]); retval = -EINVAL; break; @@ -154,7 +154,7 @@ static int uinput_validate_absbits(struct input_dev *dev) if ((dev->absflat[cnt] < dev->absmin[cnt]) || (dev->absflat[cnt] > dev->absmax[cnt])) { - printk(KERN_DEBUG + printk(KERN_DEBUG "%s: absflat[%02x] out of range: %d " "(min:%d/max:%d)\n", UINPUT_NAME, cnt, dev->absflat[cnt], @@ -190,7 +190,7 @@ static int uinput_alloc_device(struct file *file, const char *buffer, size_t cou goto exit; } - if (NULL != dev->name) + if (NULL != dev->name) kfree(dev->name); size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; @@ -229,7 +229,7 @@ exit: static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct uinput_device *udev = file->private_data; - + if (test_bit(UIST_CREATED, &(udev->state))) { struct input_event ev; @@ -247,7 +247,7 @@ static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t { struct uinput_device *udev = file->private_data; int retval = 0; - + if (!test_bit(UIST_CREATED, &(udev->state))) return -ENODEV; @@ -255,16 +255,16 @@ static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t return -EAGAIN; retval = wait_event_interruptible(udev->waitq, - (udev->head != udev->tail) || + (udev->head != udev->tail) || !test_bit(UIST_CREATED, &(udev->state))); - + if (retval) return retval; if (!test_bit(UIST_CREATED, &(udev->state))) return -ENODEV; - while ((udev->head != udev->tail) && + while ((udev->head != udev->tail) && (retval + sizeof(struct input_event) <= count)) { if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), sizeof(struct input_event))) return -EFAULT; @@ -284,7 +284,7 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) if (udev->head != udev->tail) return POLLIN | POLLRDNORM; - return 0; + return 0; } static int uinput_burn_device(struct uinput_device *udev) @@ -318,7 +318,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd case UI_DEV_CREATE: retval = uinput_create_device(udev); break; - + case UI_DEV_DESTROY: retval = uinput_destroy_device(udev); break; @@ -330,7 +330,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->evbit); break; - + case UI_SET_KEYBIT: if (arg > KEY_MAX) { retval = -EINVAL; @@ -338,7 +338,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->keybit); break; - + case UI_SET_RELBIT: if (arg > REL_MAX) { retval = -EINVAL; @@ -346,7 +346,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->relbit); break; - + case UI_SET_ABSBIT: if (arg > ABS_MAX) { retval = -EINVAL; @@ -354,7 +354,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->absbit); break; - + case UI_SET_MSCBIT: if (arg > MSC_MAX) { retval = -EINVAL; @@ -362,7 +362,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->mscbit); break; - + case UI_SET_LEDBIT: if (arg > LED_MAX) { retval = -EINVAL; @@ -370,7 +370,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->ledbit); break; - + case UI_SET_SNDBIT: if (arg > SND_MAX) { retval = -EINVAL; @@ -378,7 +378,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->sndbit); break; - + case UI_SET_FFBIT: if (arg > FF_MAX) { retval = -EINVAL; @@ -386,7 +386,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd } set_bit(arg, udev->dev->ffbit); break; - + default: retval = -EFAULT; } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 846b5e880..0063af037 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -14,6 +14,25 @@ #include "psmouse.h" #include "logips2pp.h" +/* Logitech mouse types */ +#define PS2PP_KIND_WHEEL 1 +#define PS2PP_KIND_MX 2 +#define PS2PP_KIND_TP3 3 + +/* Logitech mouse features */ +#define PS2PP_WHEEL 0x01 +#define PS2PP_HWHEEL 0x02 +#define PS2PP_SIDE_BTN 0x04 +#define PS2PP_EXTRA_BTN 0x08 +#define PS2PP_TASK_BTN 0x10 +#define PS2PP_NAV_BTN 0x20 + +struct ps2pp_info { + const int model; + unsigned const int kind; + unsigned const int features; +}; + /* * Process a PS2++ or PS2T++ packet. */ @@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse) packet[0] &= 0x0f; packet[1] = 0; packet[2] = 0; - } } @@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse) static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) { - unsigned char d; - int i; - - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + if (psmouse_sliced_command(psmouse, command)) return -1; - for (i = 6; i >= 0; i -= 2) { - d = (command >> i) & 3; - if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) return -1; @@ -99,7 +108,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha * enabled if we do nothing to it. Of course I put this in because I want it * disabled :P * 1 - enabled (if previously disabled, also default) - * 0/2 - disabled + * 0/2 - disabled */ static void ps2pp_set_smartscroll(struct psmouse *psmouse) @@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse) psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - if (psmouse_smartscroll == 1) - param[0] = 1; - else - if (psmouse_smartscroll > 2) - return; - - /* else leave param[0] == 0 to disable */ - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + if (psmouse_smartscroll < 2) { + /* 0 - disabled, 1 - enabled */ + param[0] = psmouse_smartscroll; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + } } /* @@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse) psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES); } +static struct ps2pp_info *get_model_info(unsigned char model) +{ + static struct ps2pp_info ps2pp_list[] = { + { 12, 0, PS2PP_SIDE_BTN}, + { 13, 0, 0 }, + { 40, 0, PS2PP_SIDE_BTN }, + { 41, 0, PS2PP_SIDE_BTN }, + { 42, 0, PS2PP_SIDE_BTN }, + { 43, 0, PS2PP_SIDE_BTN }, + { 50, 0, 0 }, + { 51, 0, 0 }, + { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, + { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 61, PS2PP_KIND_MX, + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */ + { 73, 0, PS2PP_SIDE_BTN }, + { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, + { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 96, 0, 0 }, + { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, + { 100, PS2PP_KIND_MX, + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */ + { 112, PS2PP_KIND_MX, + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */ + { 114, PS2PP_KIND_MX, + PS2PP_WHEEL | PS2PP_SIDE_BTN | + PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */ + { } + }; + int i; + + for (i = 0; ps2pp_list[i].model; i++) + if (model == ps2pp_list[i].model) + return &ps2pp_list[i]; + return NULL; +} + /* - * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or - * touchpad. + * Set up input device's properties based on the detected mouse model. */ -static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) +static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info) { - int i; - static struct _logips2_list { - const int model; - unsigned const int features; - } logips2pp_list [] = { - { 12, PS2PP_4BTN}, - { 13, 0 }, - { 40, PS2PP_4BTN }, - { 41, PS2PP_4BTN }, - { 42, PS2PP_4BTN }, - { 43, PS2PP_4BTN }, - { 50, 0 }, - { 51, 0 }, - { 52, PS2PP_4BTN | PS2PP_WHEEL }, - { 53, PS2PP_WHEEL }, - { 61, PS2PP_WHEEL | PS2PP_MX }, /* MX700 */ - { 73, PS2PP_4BTN }, - { 75, PS2PP_WHEEL }, - { 76, PS2PP_WHEEL }, - { 80, PS2PP_4BTN | PS2PP_WHEEL }, - { 81, PS2PP_WHEEL }, - { 83, PS2PP_WHEEL }, - { 88, PS2PP_WHEEL }, - { 96, 0 }, - { 97, 0 }, - { 100 , PS2PP_WHEEL | PS2PP_MX }, /* MX510 */ - { 112 , PS2PP_WHEEL | PS2PP_MX }, /* MX500 */ - { 114 , PS2PP_WHEEL | PS2PP_MX | PS2PP_MX310 }, /* MX310 */ - { } - }; + if (model_info->features & PS2PP_SIDE_BTN) + set_bit(BTN_SIDE, psmouse->dev.keybit); + + if (model_info->features & PS2PP_EXTRA_BTN) + set_bit(BTN_EXTRA, psmouse->dev.keybit); - psmouse->vendor = "Logitech"; - psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + if (model_info->features & PS2PP_TASK_BTN) + set_bit(BTN_TASK, psmouse->dev.keybit); - if (param[1] < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (param[1] < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); + if (model_info->features & PS2PP_NAV_BTN) { + set_bit(BTN_FORWARD, psmouse->dev.keybit); + set_bit(BTN_BACK, psmouse->dev.keybit); + } - psmouse->type = PSMOUSE_PS2; + if (model_info->features & PS2PP_WHEEL) + set_bit(REL_WHEEL, psmouse->dev.relbit); - for (i = 0; logips2pp_list[i].model; i++){ - if (logips2pp_list[i].model == psmouse->model){ - psmouse->type = PSMOUSE_PS2PP; - if (logips2pp_list[i].features & PS2PP_4BTN) - set_bit(BTN_SIDE, psmouse->dev.keybit); + if (model_info->features & PS2PP_HWHEEL) + set_bit(REL_HWHEEL, psmouse->dev.relbit); - if (logips2pp_list[i].features & PS2PP_WHEEL){ - set_bit(REL_WHEEL, psmouse->dev.relbit); - psmouse->name = "Wheel Mouse"; - } - if (logips2pp_list[i].features & PS2PP_MX) { - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(BTN_EXTRA, psmouse->dev.keybit); - set_bit(BTN_TASK, psmouse->dev.keybit); - if (!(logips2pp_list[i].features & PS2PP_MX310)){ - set_bit(BTN_BACK, psmouse->dev.keybit); - set_bit(BTN_FORWARD, psmouse->dev.keybit); - } - psmouse->name = "MX Mouse"; - } + switch (model_info->kind) { + case PS2PP_KIND_WHEEL: + psmouse->name = "Wheel Mouse"; + break; + + case PS2PP_KIND_MX: + psmouse->name = "MX Mouse"; + break; + + case PS2PP_KIND_TP3: + psmouse->name = "TouchPad 3"; break; - } } +} + + /* - * Do Logitech PS2++ / PS2T++ magic init. + * Logitech magic init. Detect whether the mouse is a Logitech one + * and its exact model and try turning on extended protocol for ones + * that support it. */ - if (psmouse->type == PSMOUSE_PS2PP) { - if (psmouse->model == 97) { /* TouchPad 3 */ +int ps2pp_init(struct psmouse *psmouse, int set_properties) +{ + unsigned char param[4]; + unsigned char protocol = PSMOUSE_PS2; + unsigned char model, buttons; + struct ps2pp_info *model_info; + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + param[1] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[1] != 0) { + model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + buttons = param[1]; + model_info = get_model_info(model); - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(REL_HWHEEL, psmouse->dev.relbit); +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + if (model == 97) { /* Touch Pad 3 */ - param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + /* Unprotect RAM */ + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + /* Enable features */ + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + /* Enable PS2++ */ + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; psmouse_command(psmouse, param, 0x30d1); param[0] = 0; if (!psmouse_command(psmouse, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { - psmouse->name = "TouchPad 3"; - return PSMOUSE_PS2TPP; + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { + protocol = PSMOUSE_PS2TPP; } - } else { + } else if (get_model_info(model) != NULL) { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ ps2pp_cmd(psmouse, param, 0xDB); - if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && - (param[2] & 3) == ((param[1] >> 2) & 3)) { - ps2pp_set_smartscroll(psmouse); - return PSMOUSE_PS2PP; + if ((param[0] & 0x78) == 0x48 && + (param[1] & 0xf3) == 0xc2 && + (param[2] & 0x03) == ((param[1] >> 2) & 3)) { + ps2pp_set_smartscroll(psmouse); + protocol = PSMOUSE_PS2PP; } } - } - return 0; -} + if (set_properties) { + psmouse->vendor = "Logitech"; + psmouse->model = model; -/* - * Logitech magic init. - */ -int ps2pp_detect(struct psmouse *psmouse) -{ - unsigned char param[4]; + if (buttons < 3) + clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + if (buttons < 2) + clear_bit(BTN_RIGHT, psmouse->dev.keybit); - param[0] = 0; - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); - param[1] = 0; - psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + if (model_info) + ps2pp_set_model_properties(psmouse, model_info); + } + } - return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0; + return protocol; } diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h index d5e05defe..959743a9e 100644 --- a/drivers/input/mouse/logips2pp.h +++ b/drivers/input/mouse/logips2pp.h @@ -11,13 +11,8 @@ #ifndef _LOGIPS2PP_H #define _LOGIPS2PP_H -#define PS2PP_4BTN 0x01 -#define PS2PP_WHEEL 0x02 -#define PS2PP_MX 0x04 -#define PS2PP_MX310 0x08 - -struct psmouse; void ps2pp_process_packet(struct psmouse *psmouse); void ps2pp_set_800dpi(struct psmouse *psmouse); -int ps2pp_detect(struct psmouse *psmouse); +int ps2pp_init(struct psmouse *psmouse, int set_properties); + #endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 3d4a30060..0b3826724 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -43,9 +43,9 @@ int psmouse_smartscroll = 1; module_param_named(smartscroll, psmouse_smartscroll, bool, 0); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); -unsigned int psmouse_resetafter; +static unsigned int psmouse_resetafter; module_param_named(resetafter, psmouse_resetafter, uint, 0); -MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never)."); +MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); __obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_resolution="); @@ -56,15 +56,22 @@ __obsolete_setup("psmouse_rate="); static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; /* - * psmouse_process_packet() analyzes the PS/2 mouse packet contents and - * reports relevant events to the input module. + * psmouse_process_byte() analyzes the PS/2 data stream and reports + * relevant events to the input module once full packet has arrived. */ -static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { struct input_dev *dev = &psmouse->dev; unsigned char *packet = psmouse->packet; + if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS)) + return PSMOUSE_GOOD_DATA; + +/* + * Full packet accumulated, process it + */ + input_regs(dev, regs); /* @@ -112,6 +119,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); input_sync(dev); + + return PSMOUSE_FULL_PACKET; } /* @@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) { struct psmouse *psmouse = serio->private; + psmouse_ret_t rc; if (psmouse->state == PSMOUSE_IGNORE) goto out; @@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->pktcnt == 2) { if (psmouse->packet[1] == PSMOUSE_RET_ID) { psmouse->state = PSMOUSE_IGNORE; - serio_rescan(serio); + serio_reconnect(serio); goto out; } if (psmouse->type == PSMOUSE_SYNAPTICS) { @@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } } - if (psmouse->type == PSMOUSE_SYNAPTICS) { - /* - * The synaptics driver has its own resync logic, - * so it needs to receive all bytes one at a time. - */ - synaptics_process_byte(psmouse, regs); - goto out; - } + rc = psmouse->protocol_handler(psmouse, regs); - if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) { - psmouse_process_packet(psmouse, regs); - psmouse->pktcnt = 0; - goto out; + switch (rc) { + case PSMOUSE_BAD_DATA: + printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", + psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse->pktcnt = 0; + + if (++psmouse->out_of_sync == psmouse_resetafter) { + psmouse->state = PSMOUSE_IGNORE; + printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); + serio_reconnect(psmouse->serio); + } + break; + + case PSMOUSE_FULL_PACKET: + psmouse->pktcnt = 0; + if (psmouse->out_of_sync) { + psmouse->out_of_sync = 0; + printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", + psmouse->name, psmouse->phys); + } + break; + + case PSMOUSE_GOOD_DATA: + break; } out: return IRQ_HANDLED; @@ -288,6 +311,30 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) } +/* + * psmouse_sliced_command() sends an extended PS/2 command to the mouse + * using sliced syntax, understood by advanced devices, such as Logitech + * or Synaptics touchpads. The command is encoded as: + * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu + * is the command. + */ +int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) +{ + int i; + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + unsigned char d = (command >> i) & 3; + if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + return 0; +} + + /* * psmouse_reset() resets the mouse into power-on state. */ @@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse) * the mouse may have. */ -static int psmouse_extensions(struct psmouse *psmouse) +static int psmouse_extensions(struct psmouse *psmouse, + unsigned int max_proto, int set_properties) { int synaptics_hardware = 0; - psmouse->vendor = "Generic"; - psmouse->name = "Mouse"; - psmouse->model = 0; - /* * Try Synaptics TouchPad */ - if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) { + if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) { synaptics_hardware = 1; - psmouse->vendor = "Synaptics"; - psmouse->name = "TouchPad"; - if (psmouse_max_proto > PSMOUSE_IMEX) { - if (synaptics_init(psmouse) == 0) + if (set_properties) { + psmouse->vendor = "Synaptics"; + psmouse->name = "TouchPad"; + } + + if (max_proto > PSMOUSE_IMEX) { + if (!set_properties || synaptics_init(psmouse) == 0) return PSMOUSE_SYNAPTICS; /* * Some Synaptics touchpads can emulate extended protocols (like IMPS/2). * Unfortunately Logitech/Genius probes confuse some firmware versions so * we'll have to skip them. */ - psmouse_max_proto = PSMOUSE_IMEX; + max_proto = PSMOUSE_IMEX; } /* * Make sure that touchpad is in relative mode, gestures (taps) are enabled @@ -395,35 +442,46 @@ static int psmouse_extensions(struct psmouse *psmouse) synaptics_reset(psmouse); } - if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { - set_bit(BTN_EXTRA, psmouse->dev.keybit); - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); + if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { + + if (set_properties) { + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(REL_WHEEL, psmouse->dev.relbit); + psmouse->vendor = "Genius"; + psmouse->name = "Wheel Mouse"; + } - psmouse->vendor = "Genius"; - psmouse->name = "Wheel Mouse"; return PSMOUSE_GENPS; } - if (psmouse_max_proto > PSMOUSE_IMEX) { - int type = ps2pp_detect(psmouse); - if (type) + if (max_proto > PSMOUSE_IMEX) { + int type = ps2pp_init(psmouse, set_properties); + if (type > PSMOUSE_PS2) return type; } - if (psmouse_max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) { - set_bit(REL_WHEEL, psmouse->dev.relbit); + if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) { - if (psmouse_max_proto >= PSMOUSE_IMEX && - im_explorer_detect(psmouse)) { + if (set_properties) { + set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit); + if (!psmouse->name) + psmouse->name = "Explorer Mouse"; + } + + return PSMOUSE_IMEX; + } + + if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) { - psmouse->name = "Explorer Mouse"; - return PSMOUSE_IMEX; + if (set_properties) { + set_bit(REL_WHEEL, psmouse->dev.relbit); + if (!psmouse->name) + psmouse->name = "Wheel Mouse"; } - psmouse->name = "Wheel Mouse"; return PSMOUSE_IMPS; } @@ -473,12 +531,7 @@ static int psmouse_probe(struct psmouse *psmouse) if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); -/* - * And here we try to determine if it has any extensions over the - * basic PS/2 3-button mouse. - */ - - return psmouse->type = psmouse_extensions(psmouse); + return 0; } /* @@ -616,7 +669,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->state = PSMOUSE_CMD_MODE; psmouse->serio = serio; psmouse->dev.private = psmouse; @@ -628,13 +680,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) return; } - if (psmouse_probe(psmouse) <= 0) { + if (psmouse_probe(psmouse) < 0) { serio_close(serio); kfree(psmouse); serio->private = NULL; return; } + psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Mouse"; + if (!psmouse->protocol_handler) + psmouse->protocol_handler = psmouse_process_byte; + sprintf(psmouse->devname, "%s %s %s", psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); sprintf(psmouse->phys, "%s/input0", @@ -668,27 +728,24 @@ static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; struct serio_dev *dev = serio->dev; - int old_type; if (!dev || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } - old_type = psmouse->type; - psmouse->state = PSMOUSE_CMD_MODE; - psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0; + psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0; if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) return -1; - } else if (psmouse_probe(psmouse) != old_type) + } else if (psmouse_probe(psmouse) < 0 || + psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) return -1; /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization */ - psmouse->type = old_type; psmouse_initialize(psmouse); if (psmouse->ptport) { diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e54841ad1..47fbc48f6 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -22,6 +22,13 @@ #define PSMOUSE_ACTIVATED 1 #define PSMOUSE_IGNORE 2 +/* psmouse protocol handler return codes */ +typedef enum { + PSMOUSE_BAD_DATA, + PSMOUSE_GOOD_DATA, + PSMOUSE_FULL_PACKET +} psmouse_ret_t; + struct psmouse; struct psmouse_ptport { @@ -45,6 +52,7 @@ struct psmouse { unsigned char type; unsigned char model; unsigned long last; + unsigned long out_of_sync; unsigned char state; char acking; volatile char ack; @@ -52,6 +60,7 @@ struct psmouse { char devname[64]; char phys[32]; + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); }; @@ -65,10 +74,10 @@ struct psmouse { #define PSMOUSE_SYNAPTICS 7 int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); +int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); int psmouse_reset(struct psmouse *psmouse); extern int psmouse_smartscroll; extern unsigned int psmouse_rate; -extern unsigned int psmouse_resetafter; #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index a182ce7f4..2bd152fe0 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -43,34 +43,12 @@ * Synaptics communications functions ****************************************************************************/ -/* - * Use the Synaptics extended ps/2 syntax to write a special command byte. - * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu - * is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd - * and synaptics_mode_cmd) - */ -static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command) -{ - int i; - - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) - return -1; - - for (i = 6; i >= 0; i -= 2) { - unsigned char d = (command >> i) & 3; - if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - - return 0; -} - /* * Send a command to the synpatics touchpad by special commands */ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) { - if (synaptics_special_cmd(psmouse, c)) + if (psmouse_sliced_command(psmouse, c)) return -1; if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) return -1; @@ -84,7 +62,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) { unsigned char param[1]; - if (synaptics_special_cmd(psmouse, mode)) + if (psmouse_sliced_command(psmouse, mode)) return -1; param[0] = SYN_PS_SET_MODE2; if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE)) @@ -118,17 +96,31 @@ static int synaptics_capability(struct psmouse *psmouse) if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) return -1; - priv->capabilities = (cap[0]<<16) | (cap[1]<<8) | cap[2]; + priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; priv->ext_cap = 0; if (!SYN_CAP_VALID(priv->capabilities)) return -1; - if (SYN_EXT_CAP_REQUESTS(priv->capabilities)) { + /* + * Unless capExtended is set the rest of the flags should be ignored + */ + if (!SYN_CAP_EXTENDED(priv->capabilities)) + priv->capabilities = 0; + + if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { printk(KERN_ERR "Synaptics claims to have extended capabilities," " but I'm not able to read them."); - } else - priv->ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2]; + } else { + priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + + /* + * if nExtBtn is greater than 8 it should be considered + * invalid and treated as 0 + */ + if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) + priv->ext_cap &= 0xff0fff; + } } return 0; } @@ -167,11 +159,12 @@ static void print_ident(struct synaptics_data *priv) if (SYN_CAP_EXTENDED(priv->capabilities)) { printk(KERN_INFO " Touchpad has extended capability bits\n"); - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && - SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) <= 8) + if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); - else if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + printk(KERN_INFO " -> middle button\n"); + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) printk(KERN_INFO " -> four buttons\n"); if (SYN_CAP_MULTIFINGER(priv->capabilities)) printk(KERN_INFO " -> multifinger detection\n"); @@ -219,21 +212,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_open(struct serio *port) -{ - return 0; -} - -static void synaptics_pt_close(struct serio *port) -{ -} - static int synaptics_pt_write(struct serio *port, unsigned char c) { struct psmouse *parent = port->driver; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ - if (synaptics_special_cmd(parent, c)) + if (psmouse_sliced_command(parent, c)) return -1; if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) return -1; @@ -289,165 +273,11 @@ static void synaptics_pt_create(struct psmouse *psmouse) port->serio.name = "Synaptics pass-through"; port->serio.phys = "synaptics-pt/serio0"; port->serio.write = synaptics_pt_write; - port->serio.open = synaptics_pt_open; - port->serio.close = synaptics_pt_close; port->serio.driver = psmouse; port->activate = synaptics_pt_activate; } -/***************************************************************************** - * Driver initialization/cleanup functions - ****************************************************************************/ - -static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) -{ - dev->absmin[axis] = min; - dev->absmax[axis] = max; - dev->absfuzz[axis] = fuzz; - dev->absflat[axis] = flat; - - set_bit(axis, dev->absbit); -} - -static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) -{ - set_bit(EV_ABS, dev->evbit); - set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); - set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); - set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - set_bit(ABS_TOOL_WIDTH, dev->absbit); - - set_bit(EV_KEY, dev->evbit); - set_bit(BTN_TOUCH, dev->keybit); - set_bit(BTN_TOOL_FINGER, dev->keybit); - set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); - - set_bit(BTN_LEFT, dev->keybit); - set_bit(BTN_RIGHT, dev->keybit); - set_bit(BTN_FORWARD, dev->keybit); - set_bit(BTN_BACK, dev->keybit); - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) { - switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { - default: - /* - * if nExtBtn is greater than 8 it should be considered - * invalid and treated as 0 - */ - break; - case 8: - set_bit(BTN_7, dev->keybit); - set_bit(BTN_6, dev->keybit); - case 6: - set_bit(BTN_5, dev->keybit); - set_bit(BTN_4, dev->keybit); - case 4: - set_bit(BTN_3, dev->keybit); - set_bit(BTN_2, dev->keybit); - case 2: - set_bit(BTN_1, dev->keybit); - set_bit(BTN_0, dev->keybit); - break; - } - } - - clear_bit(EV_REL, dev->evbit); - clear_bit(REL_X, dev->relbit); - clear_bit(REL_Y, dev->relbit); -} - -void synaptics_reset(struct psmouse *psmouse) -{ - /* reset touchpad back to relative mode, gestures enabled */ - synaptics_mode_cmd(psmouse, 0); -} - -static void synaptics_disconnect(struct psmouse *psmouse) -{ - synaptics_reset(psmouse); - kfree(psmouse->private); -} - -static int synaptics_reconnect(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - struct synaptics_data old_priv = *priv; - - if (!synaptics_detect(psmouse)) - return -1; - - if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); - return -1; - } - - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) - return -1; - - if (synaptics_set_mode(psmouse, 0)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); - return -1; - } - - return 0; -} - -int synaptics_detect(struct psmouse *psmouse) -{ - unsigned char param[4]; - - param[0] = 0; - - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); - psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); - - return param[1] == 0x47; -} - -int synaptics_init(struct psmouse *psmouse) -{ - struct synaptics_data *priv; - - psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL); - if (!priv) - return -1; - memset(priv, 0, sizeof(struct synaptics_data)); - - if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); - goto init_fail; - } - - if (synaptics_set_mode(psmouse, 0)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); - goto init_fail; - } - - priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - - if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities)) - synaptics_pt_create(psmouse); - - print_ident(priv); - set_input_params(&psmouse->dev, priv); - - psmouse->disconnect = synaptics_disconnect; - psmouse->reconnect = synaptics_reconnect; - - return 0; - - init_fail: - kfree(priv); - return -1; -} - /***************************************************************************** * Functions to interpret the absolute mode packets ****************************************************************************/ @@ -471,17 +301,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; - if (SYN_CAP_EXTENDED(priv->capabilities) && - (SYN_CAP_FOUR_BUTTON(priv->capabilities))) { - hw->up = ((buf[3] & 0x01)) ? 1 : 0; - if (hw->left) - hw->up = !hw->up; - hw->down = ((buf[3] & 0x02)) ? 1 : 0; - if (hw->right) - hw->down = !hw->down; + + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; + + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; + hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } + if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && - ((buf[3] & 2) ? !hw->right : hw->right)) { + ((buf[0] ^ buf[3]) & 0x02)) { switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { default: /* @@ -490,17 +320,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data */ break; case 8: - hw->b7 = ((buf[5] & 0x08)) ? 1 : 0; - hw->b6 = ((buf[4] & 0x08)) ? 1 : 0; + hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0; + hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0; case 6: - hw->b5 = ((buf[5] & 0x04)) ? 1 : 0; - hw->b4 = ((buf[4] & 0x04)) ? 1 : 0; + hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0; + hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0; case 4: - hw->b3 = ((buf[5] & 0x02)) ? 1 : 0; - hw->b2 = ((buf[4] & 0x02)) ? 1 : 0; + hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0; + hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0; case 2: - hw->b1 = ((buf[5] & 0x01)) ? 1 : 0; - hw->b0 = ((buf[4] & 0x01)) ? 1 : 0; + hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0; + hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0; } } } else { @@ -525,6 +355,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) struct synaptics_hw_state hw; int num_fingers; int finger_width; + int i; synaptics_parse_hw_state(psmouse->packet, priv, &hw); @@ -570,32 +401,20 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); - input_report_key(dev, BTN_LEFT, hw.left); - input_report_key(dev, BTN_RIGHT, hw.right); - input_report_key(dev, BTN_FORWARD, hw.up); - input_report_key(dev, BTN_BACK, hw.down); - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) - switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { - default: - /* - * if nExtBtn is greater than 8 it should be considered - * invalid and treated as 0 - */ - break; - case 8: - input_report_key(dev, BTN_7, hw.b7); - input_report_key(dev, BTN_6, hw.b6); - case 6: - input_report_key(dev, BTN_5, hw.b5); - input_report_key(dev, BTN_4, hw.b4); - case 4: - input_report_key(dev, BTN_3, hw.b3); - input_report_key(dev, BTN_2, hw.b2); - case 2: - input_report_key(dev, BTN_1, hw.b1); - input_report_key(dev, BTN_0, hw.b0); - break; - } + input_report_key(dev, BTN_LEFT, hw.left); + input_report_key(dev, BTN_RIGHT, hw.right); + + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + input_report_key(dev, BTN_MIDDLE, hw.middle); + + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + input_report_key(dev, BTN_FORWARD, hw.up); + input_report_key(dev, BTN_BACK, hw.down); + } + + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); + input_sync(dev); } @@ -607,6 +426,9 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + if (idx < 0 || idx > 4) + return 0; + switch (pkt_type) { case SYN_NEWABS: case SYN_NEWABS_RELAXED: @@ -637,7 +459,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) return SYN_NEWABS_STRICT; } -void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { struct input_dev *dev = &psmouse->dev; struct synaptics_data *priv = psmouse->private; @@ -645,11 +467,6 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) input_regs(dev, regs); if (psmouse->pktcnt >= 6) { /* Full packet received */ - if (priv->out_of_sync) { - priv->out_of_sync = 0; - printk(KERN_NOTICE "Synaptics driver resynced.\n"); - } - if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); @@ -657,16 +474,142 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); else synaptics_process_packet(psmouse); - psmouse->pktcnt = 0; - - } else if (psmouse->pktcnt && - !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) { - printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); - psmouse->pktcnt = 0; - if (++priv->out_of_sync == psmouse_resetafter) { - psmouse->state = PSMOUSE_IGNORE; - printk(KERN_NOTICE "synaptics: issuing reconnect request\n"); - serio_reconnect(psmouse->serio); - } + + return PSMOUSE_FULL_PACKET; + } + + return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ? + PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; +} + +/***************************************************************************** + * Driver initialization/cleanup functions + ****************************************************************************/ +static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) +{ + int i; + + set_bit(EV_ABS, dev->evbit); + input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); + set_bit(ABS_TOOL_WIDTH, dev->absbit); + + set_bit(EV_KEY, dev->evbit); + set_bit(BTN_TOUCH, dev->keybit); + set_bit(BTN_TOOL_FINGER, dev->keybit); + set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); + set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); + + set_bit(BTN_LEFT, dev->keybit); + set_bit(BTN_RIGHT, dev->keybit); + + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + set_bit(BTN_MIDDLE, dev->keybit); + + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + set_bit(BTN_FORWARD, dev->keybit); + set_bit(BTN_BACK, dev->keybit); + } + + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + set_bit(BTN_0 + i, dev->keybit); + + clear_bit(EV_REL, dev->evbit); + clear_bit(REL_X, dev->relbit); + clear_bit(REL_Y, dev->relbit); +} + +void synaptics_reset(struct psmouse *psmouse) +{ + /* reset touchpad back to relative mode, gestures enabled */ + synaptics_mode_cmd(psmouse, 0); +} + +static void synaptics_disconnect(struct psmouse *psmouse) +{ + synaptics_reset(psmouse); + kfree(psmouse->private); +} + +static int synaptics_reconnect(struct psmouse *psmouse) +{ + struct synaptics_data *priv = psmouse->private; + struct synaptics_data old_priv = *priv; + + if (!synaptics_detect(psmouse)) + return -1; + + if (synaptics_query_hardware(psmouse)) { + printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + return -1; + } + + if (old_priv.identity != priv->identity || + old_priv.model_id != priv->model_id || + old_priv.capabilities != priv->capabilities || + old_priv.ext_cap != priv->ext_cap) + return -1; + + if (synaptics_set_mode(psmouse, 0)) { + printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + return -1; + } + + return 0; +} + +int synaptics_detect(struct psmouse *psmouse) +{ + unsigned char param[4]; + + param[0] = 0; + + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + return param[1] == 0x47; +} + +int synaptics_init(struct psmouse *psmouse) +{ + struct synaptics_data *priv; + + psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL); + if (!priv) + return -1; + memset(priv, 0, sizeof(struct synaptics_data)); + + if (synaptics_query_hardware(psmouse)) { + printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + goto init_fail; + } + + if (synaptics_set_mode(psmouse, 0)) { + printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + goto init_fail; } + + priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + + if (SYN_CAP_PASS_THROUGH(priv->capabilities)) + synaptics_pt_create(psmouse); + + print_ident(priv); + set_input_params(&psmouse->dev, priv); + + psmouse->protocol_handler = synaptics_process_byte; + psmouse->disconnect = synaptics_disconnect; + psmouse->reconnect = synaptics_reconnect; + + return 0; + + init_fail: + kfree(priv); + return -1; } + + diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 69764deb6..eb64431a7 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -9,7 +9,6 @@ #ifndef _SYNAPTICS_H #define _SYNAPTICS_H -extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs); extern int synaptics_detect(struct psmouse *psmouse); extern int synaptics_init(struct psmouse *psmouse); extern void synaptics_reset(struct psmouse *psmouse); @@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse); /* synaptics capability bits */ #define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) +#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) #define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) #define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) -#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1) +#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) /* synaptics modes query bits */ @@ -86,18 +86,12 @@ struct synaptics_hw_state { int y; int z; int w; - int left; - int right; - int up; - int down; - int b0; - int b1; - int b2; - int b3; - int b4; - int b5; - int b6; - int b7; + unsigned int left:1; + unsigned int right:1; + unsigned int middle:1; + unsigned int up:1; + unsigned int down:1; + unsigned char ext_buttons; }; struct synaptics_data { @@ -108,7 +102,6 @@ struct synaptics_data { unsigned long int identity; /* Identification */ /* Data for normal processing */ - unsigned int out_of_sync; /* # of packets out of sync */ int old_w; /* Previous w value */ unsigned char pkt_type; /* packet type - old, new, etc */ }; diff --git a/drivers/input/power.c b/drivers/input/power.c index 552dcd870..f7469b55e 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -1,7 +1,7 @@ /* * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ * - * Copyright (c) 2001 "Crazy" James Simmons + * Copyright (c) 2001 "Crazy" James Simmons * * Input driver Power Management. * @@ -51,7 +51,7 @@ static void suspend_button_task_handler(void *data) static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); -static void power_event(struct input_handle *handle, unsigned int type, +static void power_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) { struct input_dev *dev = handle->dev; @@ -73,7 +73,7 @@ static void power_event(struct input_handle *handle, unsigned int type, case KEY_POWER: /* Hum power down the machine. */ break; - default: + default: return; } } else { @@ -83,9 +83,9 @@ static void power_event(struct input_handle *handle, unsigned int type, /* This is risky. See pm.h for details. */ if (dev->state != PM_RESUME) dev->state = PM_RESUME; - else - dev->state = PM_SUSPEND; - pm_send(dev->pm_dev, dev->state, dev); + else + dev->state = PM_SUSPEND; + pm_send(dev->pm_dev, dev->state, dev); break; case KEY_POWER: /* Turn the input device off completely ? */ @@ -97,14 +97,14 @@ static void power_event(struct input_handle *handle, unsigned int type, return; } -static struct input_handle *power_connect(struct input_handler *handler, - struct input_dev *dev, +static struct input_handle *power_connect(struct input_handler *handler, + struct input_dev *dev, struct input_device_id *id) { struct input_handle *handle; if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit)) - return NULL; + return NULL; if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit))) return NULL; @@ -133,21 +133,21 @@ static struct input_device_id power_ids[] = { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } - }, + }, { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } - }, + }, { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_PWR) }, - }, + }, { }, /* Terminating entry */ }; MODULE_DEVICE_TABLE(input, power_ids); - + static struct input_handler power_handler = { .event = power_event, .connect = power_connect, @@ -172,3 +172,4 @@ module_exit(power_exit); MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Input Power Management driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/serio/98kbd-io.c b/drivers/input/serio/98kbd-io.c index 25f64c999..32bd067a9 100644 --- a/drivers/input/serio/98kbd-io.c +++ b/drivers/input/serio/98kbd-io.c @@ -42,8 +42,8 @@ MODULE_LICENSE("GPL"); * Register numbers. */ -#define KBD98_COMMAND_REG 0x43 -#define KBD98_STATUS_REG 0x43 +#define KBD98_COMMAND_REG 0x43 +#define KBD98_STATUS_REG 0x43 #define KBD98_DATA_REG 0x41 spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED; @@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED; static struct serio kbd98_port; extern struct pt_regs *kbd_pt_regs; -static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* * kbd98_flush() flushes all data that may be in the keyboard buffers @@ -143,7 +143,7 @@ static struct serio kbd98_port = * to the upper layers. */ -static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; unsigned char data; @@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock_irqrestore(&kbd98io_lock, flags); serio_interrupt(&kbd98_port, data, 0, regs); + return IRQ_HANDLED; } int __init kbd98io_init(void) diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index b7fc99e5b..2234ff39d 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 6f6bf4296..48a0ad587 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -16,7 +16,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * + * * TODO: * - Dino testing (did HP ever shipped a machine on which this port * was usable/enabled ?) @@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); #define PFX "gscps2.c: " -/* +/* * Driver constants */ @@ -222,7 +222,7 @@ static LIST_HEAD(ps2port_list); /** * gscps2_interrupt() - Interruption service routine * - * This function reads received PS/2 bytes and processes them on + * This function reads received PS/2 bytes and processes them on * all interfaces. * The problematic part here is, that the keyboard and mouse PS/2 port * share the same interrupt and it's not possible to send data if any @@ -240,9 +240,9 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) unsigned long flags; spin_lock_irqsave(&ps2port->lock, flags); - while ( (ps2port->buffer[ps2port->append].str = + while ( (ps2port->buffer[ps2port->append].str = gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { - ps2port->buffer[ps2port->append].data = + ps2port->buffer[ps2port->append].data = gscps2_readb_input(ps2port->addr); ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); } @@ -349,7 +349,7 @@ static int __init gscps2_probe(struct parisc_device *dev) if (!dev->irq) return -ENODEV; - + /* Offset for DINO PS/2. Works with LASI even */ if (dev->id.sversion == 0x96) hpa += GSC_DINO_OFFSET; @@ -368,7 +368,7 @@ static int __init gscps2_probe(struct parisc_device *dev) gscps2_reset(ps2port); ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", - gscps2_serio_port.name, + gscps2_serio_port.name, (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); @@ -401,9 +401,9 @@ static int __init gscps2_probe(struct parisc_device *dev) ps2port->port.phys); serio_register_port(&ps2port->port); - + return 0; - + fail: free_irq(dev->irq, ps2port); @@ -430,7 +430,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev) list_del(&ps2port->node); iounmap(ps2port->addr); #if 0 - release_mem_region(dev->hpa, GSC_STATUS + 4); + release_mem_region(dev->hpa, GSC_STATUS + 4); #endif dev_set_drvdata(&dev->dev, NULL); kfree(ps2port); @@ -441,7 +441,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev) static struct parisc_device_id gscps2_device_tbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ #ifdef DINO_TESTED - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ #endif { 0, } /* 0 terminated list */ }; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index efe3c289b..e9d8dabd1 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -150,7 +150,7 @@ static int i8042_flush(void) */ static int i8042_command(unsigned char *param, int command) -{ +{ unsigned long flags; int retval = 0, i = 0; @@ -161,7 +161,7 @@ static int i8042_command(unsigned char *param, int command) dbg("%02x -> i8042 (command)", command & 0xff); i8042_write_command(command & 0xff); } - + if (!retval) for (i = 0; i < ((command >> 12) & 0xf); i++) { if ((retval = i8042_wait_write())) break; @@ -172,7 +172,7 @@ static int i8042_command(unsigned char *param, int command) if (!retval) for (i = 0; i < ((command >> 8) & 0xf); i++) { if ((retval = i8042_wait_read())) break; - if (i8042_read_status() & I8042_STR_AUXDATA) + if (i8042_read_status() & I8042_STR_AUXDATA) param[i] = ~i8042_read_data(); else param[i] = i8042_read_data(); @@ -415,17 +415,17 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else dfl = 0; dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, + data, (str >> 6), irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); - + goto irq_ret; } dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", - data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); @@ -474,8 +474,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9) return -1; param = 0xa4; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) { + +/* + * Do another loop test with the 0x5a value. Doing anything else upsets + * Profusion/ServerWorks OSB4 chipsets. + */ + + param = 0x5a; + i8042_command(¶m, I8042_CMD_AUX_LOOP); return -1; + } if (mux_version) *mux_version = ~param; @@ -530,10 +539,10 @@ static int __init i8042_check_mux(struct i8042_values *values) if (i8042_enable_mux_mode(values, &mux_version)) return -1; - + /* Workaround for broken chips which seem to support MUX, but in reality don't. */ - /* They all report version 12.10 */ - if (mux_version == 0xCA) + /* They all report version 10.12 */ + if (mux_version == 0xAC) return -1; printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", @@ -598,7 +607,7 @@ static int __init i8042_check_aux(struct i8042_values *values) /* * Bit assignment test - filters out PS/2 i8042's in AT mode */ - + if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) return -1; if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) { @@ -609,7 +618,7 @@ static int __init i8042_check_aux(struct i8042_values *values) if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) return -1; if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) - return -1; + return -1; /* * Disable the interface. @@ -639,7 +648,7 @@ static int __init i8042_port_register(struct i8042_values *values, struct serio if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); values->exists = 0; - return -1; + return -1; } printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", @@ -868,7 +877,7 @@ static int i8042_controller_resume(void) static int i8042_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if (code==SYS_DOWN || code==SYS_HALT) + if (code == SYS_DOWN || code == SYS_HALT) i8042_controller_cleanup(); return NOTIFY_DONE; } @@ -997,19 +1006,18 @@ void __exit i8042_exit(void) sysdev_class_unregister(&kbc_sysclass); } - del_timer_sync(&i8042_timer); - i8042_controller_cleanup(); - + if (i8042_kbd_values.exists) serio_unregister_port(&i8042_kbd_port); if (i8042_aux_values.exists) serio_unregister_port(&i8042_aux_port); - + for (i = 0; i < 4; i++) if (i8042_mux_values[i].exists) serio_unregister_port(i8042_mux_port + i); + del_timer_sync(&i8042_timer); i8042_platform_exit(); } diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 1df2dd1d2..5f25b21be 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c) return 0; } -static int parkbd_open(struct serio *port) -{ - return 0; -} - -static void parkbd_close(struct serio *port) -{ -} - static struct serio parkbd_port = { .write = parkbd_write, - .open = parkbd_open, - .close = parkbd_close, .name = parkbd_name, .phys = parkbd_phys, }; @@ -115,7 +104,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) parkbd_writing = 0; parkbd_writelines(3); return; - } + } parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2); @@ -131,7 +120,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) { parkbd_counter = 0; parkbd_buffer = 0; - } + } parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 021763a3e..7f4a26287 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -4,7 +4,7 @@ * Copyright (c) 2000-2001 Vojtech Pavlik * * Based on the work of: - * Richard Zidlicky + * Richard Zidlicky */ /* @@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); - -static int q40kbd_open(struct serio *port) -{ - return 0; -} -static void q40kbd_close(struct serio *port) -{ -} - static struct serio q40kbd_port = { .type = SERIO_8042, .name = "Q40 kbd port", .phys = "Q40", .write = NULL, - .open = q40kbd_open, - .close = q40kbd_close, }; static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index bcd1aa89a..a2e4be7ae 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -98,7 +98,7 @@ static int rpckbd_open(struct serio *port) static void rpckbd_close(struct serio *port) { free_irq(IRQ_KEYBOARDRX, port); - free_irq(IRQ_KEYBOARDTX, port); + free_irq(IRQ_KEYBOARDTX, port); } static struct serio rpckbd_port = diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 13d21bf45..6f003197b 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -11,18 +11,18 @@ /* * 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 + * 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 - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -108,7 +108,7 @@ void serio_handle_events(void) struct serio_event *event; list_for_each_safe(node, next, &serio_event_list) { - event = container_of(node, struct serio_event, node); + event = container_of(node, struct serio_event, node); down(&serio_sem); if (event->serio == NULL) @@ -152,7 +152,7 @@ static int serio_thread(void *nothing) do { serio_handle_events(); - wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); + wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); if (current->flags & PF_FREEZE) refrigerator(PF_FREEZE); } while (!signal_pending(current)); @@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev) int serio_open(struct serio *serio, struct serio_dev *dev) { serio->dev = dev; - if (serio->open(serio)) { + if (serio->open && serio->open(serio)) { serio->dev = NULL; return -1; } @@ -303,7 +303,8 @@ int serio_open(struct serio *serio, struct serio_dev *dev) /* called from serio_dev->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { - serio->close(serio); + if (serio->close) + serio->close(serio); serio->dev = NULL; } diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 9aec2e1d1..775914980 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -124,12 +124,10 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) memset(gunze, 0, sizeof(struct gunze)); init_input_dev(&gunze->dev); - gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72; - gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000; + input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0); gunze->serio = serio; serio->private = gunze; diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 2f2855a5c..7b4c16d6f 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -1,11 +1,11 @@ /* * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $ * - * Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com + * Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com * - * Sponsored by Transvirtual Technology. - * - * Derived from the code in h3600_ts.[ch] by Charles Flynn + * Sponsored by Transvirtual Technology. + * + * Derived from the code in h3600_ts.[ch] by Charles Flynn */ /* @@ -45,6 +45,10 @@ #include #include +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("H3600 touchscreen driver"); +MODULE_LICENSE("GPL"); + /* * Definitions & global arrays. */ @@ -75,7 +79,7 @@ #define MAX_ID 14 #define H3600_MAX_LENGTH 16 -#define H3600_KEY 0xf +#define H3600_KEY 0xf #define H3600_SCANCODE_RECORD 1 /* 1 -> record button */ #define H3600_SCANCODE_CALENDAR 2 /* 2 -> calendar */ @@ -103,7 +107,7 @@ struct h3600_dev { char phys[32]; }; -static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs) { int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; struct input_dev *dev = (struct input_dev *) dev_id; @@ -111,21 +115,25 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) input_regs(dev, regs); input_report_key(dev, KEY_ENTER, down); input_sync(dev); + + return IRQ_HANDLED; } -static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) { int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; struct input_dev *dev = (struct input_dev *) dev_id; - /* - * This interrupt is only called when we release the key. So we have + /* + * This interrupt is only called when we release the key. So we have * to fake a key press. - */ + */ input_regs(dev, regs); input_report_key(dev, KEY_SUSPEND, 1); - input_report_key(dev, KEY_SUSPEND, down); + input_report_key(dev, KEY_SUSPEND, down); input_sync(dev); + + return IRQ_HANDLED; } #ifdef CONFIG_PM @@ -141,21 +149,21 @@ enum flite_pwr { * h3600_flite_power: enables or disables power to frontlight, using last bright */ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) { - unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness); + unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness; struct h3600_dev *ts = dev->private; - /* Must be in this order */ + /* Must be in this order */ ts->serio->write(ts->serio, 1); ts->serio->write(ts->serio, pwr); - ts->serio->write(ts->serio, brightness); + ts->serio->write(ts->serio, brightness); return 0; } static int suspended = 0; -static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, +static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) { - struct input_dev *dev = (struct input_dev *) data; + struct input_dev *dev = (struct input_dev *) data; switch (req) { case PM_SUSPEND: /* enter D1-D3 */ @@ -183,7 +191,7 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, /* * This function translates the native event packets to linux input event * packets. Some packets coming from serial are not touchscreen related. In - * this case we send them off to be processed elsewhere. + * this case we send them off to be processed elsewhere. */ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) { @@ -206,7 +214,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) Note: This is true for non interrupt generated key events. */ case KEYBD_ID: - down = (ts->buf[0] & 0x80) ? 0 : 1; + down = (ts->buf[0] & 0x80) ? 0 : 1; switch (ts->buf[0] & 0x7f) { case H3600_SCANCODE_RECORD: @@ -218,7 +226,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) case H3600_SCANCODE_CONTACTS: key = KEY_PROG2; break; - case H3600_SCANCODE_Q: + case H3600_SCANCODE_Q: key = KEY_Q; break; case H3600_SCANCODE_START: @@ -237,9 +245,9 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) key = KEY_DOWN; break; default: - key = 0; - } - if (key) + key = 0; + } + if (key) input_report_key(dev, key, down); break; /* @@ -251,13 +259,13 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) * byte 0 1 2 3 */ case TOUCHS_ID: - if (!touched) { + if (!touched) { input_report_key(dev, BTN_TOUCH, 1); touched = 1; - } + } if (ts->len) { - unsigned short x, y; + unsigned short x, y; x = ts->buf[0]; x <<= 8; x += ts->buf[1]; y = ts->buf[2]; y <<= 8; y += ts->buf[3]; @@ -267,7 +275,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) } else { input_report_key(dev, BTN_TOUCH, 0); touched = 0; - } + } break; default: /* Send a non input event elsewhere */ @@ -280,7 +288,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) /* * h3600ts_event() handles events from the input module. */ -static int h3600ts_event(struct input_dev *dev, unsigned int type, +static int h3600ts_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct h3600_dev *ts = dev->private; @@ -290,7 +298,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, // ts->serio->write(ts->serio, SOME_CMD); return 0; } - } + } return -1; } @@ -317,19 +325,19 @@ static int state; #define STATE_DATA 2 /* state where we decode data */ #define STATE_EOF 3 /* state where we decode checksum or EOF */ -static void h3600ts_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) +static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, + unsigned int flags, struct pt_regs *regs) { struct h3600_dev *ts = serio->private; /* - * We have a new frame coming in. + * We have a new frame coming in. */ switch (state) { case STATE_SOF: if (data == CHAR_SOF) - state = STATE_ID; - return; + state = STATE_ID; + break; case STATE_ID: ts->event = (data & 0xf0) >> 4; ts->len = (data & 0xf); @@ -339,23 +347,25 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, break; } ts->chksum = data; - state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF; + state = (ts->len > 0) ? STATE_DATA : STATE_EOF; break; case STATE_DATA: ts->chksum += data; ts->buf[ts->idx]= data; - if(++ts->idx == ts->len) + if(++ts->idx == ts->len) state = STATE_EOF; break; case STATE_EOF: state = STATE_SOF; - if (data == CHAR_EOF || data == ts->chksum ) - h3600ts_process_packet(ts); + if (data == CHAR_EOF || data == ts->chksum) + h3600ts_process_packet(ts, regs); break; default: printk("Error3\n"); break; } + + return IRQ_HANDLED; } /* @@ -378,11 +388,11 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) init_input_dev(&ts->dev); /* Device specific stuff */ - set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES ); - set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE ); + set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES); + set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE); if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, - SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, + SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); kfree(ts); @@ -390,24 +400,19 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, - SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, + SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_suspend", &ts->dev)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); kfree(ts); return; } + /* Now we have things going we setup our input device */ ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); - ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - ts->dev.ledbit[0] = BIT(LED_SLEEP); - - ts->dev.absmin[ABS_X] = 60; ts->dev.absmin[ABS_Y] = 35; - ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024; - ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0; - - ts->serio = serio; - serio->private = ts; + ts->dev.ledbit[0] = BIT(LED_SLEEP); + input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0); + input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0); set_bit(KEY_RECORD, ts->dev.keybit); set_bit(KEY_Q, ts->dev.keybit); @@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); + ts->serio = serio; + serio->private = ts; + sprintf(ts->phys, "%s/input0", serio->phys); ts->dev.event = h3600ts_event; @@ -442,7 +450,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) //h3600_flite_control(1, 25); /* default brightness */ #ifdef CONFIG_PM - ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, + ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, h3600ts_pm_callback); printk("registered pm callback\n"); #endif @@ -458,7 +466,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) static void h3600ts_disconnect(struct serio *serio) { struct h3600_dev *ts = serio->private; - + free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev); input_unregister_device(&ts->dev); diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index 5fd47f618..8b5822c42 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -104,9 +104,12 @@ reset_netjet_s(struct IsdnCardState *cs) cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); mdelay(10); - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ /* now edge triggered for TJ320 GE 13/07/00 */ /* see comment in IRQ function */ + if (cs->subtyp) /* TJ320 */ + cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ + else + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); mdelay(10); cs->hw.njet.auxd = 0; @@ -151,7 +154,7 @@ static struct pci_dev *dev_netjet __initdata = NULL; int __init setup_netjet_s(struct IsdnCard *card) { - int bytecnt; + int bytecnt,cfg; struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -183,6 +186,15 @@ setup_netjet_s(struct IsdnCard *card) printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); return(0); } + /* the TJ300 and TJ320 must be detected, the IRQ handling is different + * unfortunatly the chips use the same device ID, but the TJ320 has + * the bit20 in status PCI cfg register set + */ + pci_read_config_dword(dev_netjet, 0x04, &cfg); + if (cfg & 0x00100000) + cs->subtyp = 1; /* TJ320 */ + else + cs->subtyp = 0; /* TJ300 */ /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */ if ((dev_netjet->subsystem_vendor == 0x55) && (dev_netjet->subsystem_device == 0x02)) { @@ -240,8 +252,8 @@ setup_netjet_s(struct IsdnCard *card) bytecnt = 256; printk(KERN_INFO - "NETjet-S: PCI card configured at %#lx IRQ %d\n", - cs->hw.njet.base, cs->irq); + "NETjet-S: %s card configured at %#lx IRQ %d\n", + cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq); if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) { printk(KERN_WARNING "HiSax: %s config port %#lx-%#lx already in use\n", diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index daec60351..1b95f6005 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -386,7 +386,7 @@ isdn_all_eaz(int di, int ch) * Begin of a CAPI like LL<->HL interface, currently used only for * supplementary service (CAPI 2.0 part III) */ -#include +#include int isdn_capi_rec_hl_msg(capi_msg *cm) { diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 26995e2d5..a61e91ac7 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -396,7 +396,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) return 0; } -static ssize_t fops_read(struct file *file, char *data, size_t count, loff_t *ppos) +static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7146_fh *fh = file->private_data; diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 02dc94dca..20d86a8c4 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -190,6 +190,7 @@ static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwi static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} }; static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo); +static int errno; static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data) diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c new file mode 100644 index 000000000..a10f92126 --- /dev/null +++ b/drivers/mtd/maps/ixp4xx.c @@ -0,0 +1,244 @@ +/* + * $Id: ixp4xx.c,v 1.1 2004/05/13 22:21:26 dsaxena Exp $ + * + * drivers/mtd/maps/ixp4xx.c + * + * MTD Map file for IXP4XX based systems. Please do not make per-board + * changes in here. If your board needs special setup, do it in your + * platform level code in arch/arm/mach-ixp4xx/board-setup.c + * + * Original Author: Intel Corporation + * Maintainer: Deepak Saxena + * + * Copyright (C) 2002 Intel Corporation + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef __ARMEB__ +#define BYTE0(h) ((h) & 0xFF) +#define BYTE1(h) (((h) >> 8) & 0xFF) +#else +#define BYTE0(h) (((h) >> 8) & 0xFF) +#define BYTE1(h) ((h) & 0xFF) +#endif + +static __u16 +ixp4xx_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *) (map->map_priv_1 + ofs); +} + +/* + * The IXP4xx expansion bus only allows 16-bit wide acceses + * when attached to a 16-bit wide device (such as the 28F128J3A), + * so we can't just memcpy_fromio(). + */ +static void +ixp4xx_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + int i; + u8 *dest = (u8 *) to; + u16 *src = (u16 *) (map->map_priv_1 + from); + u16 data; + + for (i = 0; i < (len / 2); i++) { + data = src[i]; + dest[i * 2] = BYTE0(data); + dest[i * 2 + 1] = BYTE1(data); + } + + if (len & 1) + dest[len - 1] = BYTE0(src[i]); +} + +static void +ixp4xx_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *) (map->map_priv_1 + adr) = d; +} + +struct ixp4xx_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *res; +}; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int +ixp4xx_flash_remove(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct flash_platform_data *plat = dev->dev.platform_data; + struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + if(!info) + return 0; + + /* + * This is required for a soft reboot to work. + */ + ixp4xx_write16(&info->map, 0xff, 0x55 * 0x2); + + if (info->mtd) { + del_mtd_partitions(info->mtd); + map_destroy(info->mtd); + } + if (info->map.map_priv_1) + iounmap((void *) info->map.map_priv_1); + + if (info->partitions) + kfree(info->partitions); + + if (info->res) { + release_resource(info->res); + kfree(info->res); + } + + if (plat->exit) + plat->exit(); + + /* Disable flash write */ + *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE; + + return 0; +} + +static int ixp4xx_flash_probe(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + struct flash_platform_data *plat = dev->dev.platform_data; + struct ixp4xx_flash_info *info; + int err = -1; + + if (!plat) + return -ENODEV; + + if (plat->init) { + err = plat->init(); + if (err) + return err; + } + + info = kmalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL); + if(!info) { + err = -ENOMEM; + goto Error; + } + memzero(info, sizeof(struct ixp4xx_flash_info)); + + dev_set_drvdata(&dev->dev, info); + + /* + * Enable flash write + * TODO: Move this out to board specific code + */ + *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; + + /* + * Tell the MTD layer we're not 1:1 mapped so that it does + * not attempt to do a direct access on us. + */ + info->map.phys = NO_XIP; + info->map.size = dev->resource->end - dev->resource->start + 1; + + /* + * We only support 16-bit accesses for now. If and when + * any board use 8-bit access, we'll fixup the driver to + * handle that. + */ + info->map.buswidth = 2; + info->map.name = dev->dev.bus_id; + info->map.read16 = ixp4xx_read16, + info->map.write16 = ixp4xx_write16, + info->map.copy_from = ixp4xx_copy_from, + + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, + "IXP4XXFlash"); + if (!info->res) { + printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); + err = -ENOMEM; + goto Error; + } + + info->map.map_priv_1 = + (unsigned long) ioremap(dev->resource->start, + dev->resource->end - dev->resource->start + 1); + if (!info->map.map_priv_1) { + printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); + err = -EIO; + goto Error; + } + + info->mtd = do_map_probe(plat->map_name, &info->map); + if (!info->mtd) { + printk(KERN_ERR "IXP4XXFlash: map_probe failed\n"); + err = -ENXIO; + goto Error; + } + info->mtd->owner = THIS_MODULE; + + err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, err); + if(err) + printk(KERN_ERR "Could not parse partitions\n"); + } + + if (err) + goto Error; + + return 0; + +Error: + ixp4xx_flash_remove(_dev); + return err; +} + +static struct device_driver ixp4xx_flash_driver = { + .name = "IXP4XX-Flash", + .bus = &platform_bus_type, + .probe = ixp4xx_flash_probe, + .remove = ixp4xx_flash_remove, +}; + +static int __init ixp4xx_flash_init(void) +{ + return driver_register(&ixp4xx_flash_driver); +} + +static void __exit ixp4xx_flash_exit(void) +{ + driver_unregister(&ixp4xx_flash_driver); +} + + +module_init(ixp4xx_flash_init); +module_exit(ixp4xx_flash_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems") +MODULE_AUTHOR("Deepak Saxena"); + diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index c7e25466c..5f7bdd883 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c @@ -15,11 +15,12 @@ #include #include #include -#include #include #include #include +#include #include +#include #define ROM_ADDR 0x00000000 diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c new file mode 100644 index 000000000..1901302d4 --- /dev/null +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -0,0 +1,167 @@ +/* + * $Id: wr_sbc82xx_flash.c,v 1.1 2004/06/07 10:21:32 dwmw2 Exp $ + * + * Map for flash chips on Wind River PowerQUICC II SBC82xx board. + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Author: David Woodhouse + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct mtd_info *sbcmtd[3]; +static struct mtd_partition *sbcmtd_parts[3]; + +struct map_info sbc82xx_flash_map[3] = { + {.name = "Boot flash"}, + {.name = "Alternate boot flash"}, + {.name = "User flash"} +}; + +static struct mtd_partition smallflash_parts[] = { + { + .name = "space", + .size = 0x100000, + .offset = 0, + }, { + .name = "bootloader", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; + +static struct mtd_partition bigflash_parts[] = { + { + .name = "bootloader", + .size = 0x80000, + .offset = 0, + }, { + .name = "file system", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; + +static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; + +int __init init_sbc82xx_flash(void) +{ + volatile memctl8260_t *mc = &immr->im_memctl; + int bigflash; + int i; + + /* First, register the boot flash, whichever we're booting from */ + if ((mc->memc_br0 & 0x00001800) == 0x00001800) { + bigflash = 0; + } else if ((mc->memc_br0 & 0x00001800) == 0x00000800) { + bigflash = 1; + } else { + printk(KERN_WARNING "Bus Controller register BR0 is %08x. Cannot determine flash configuration\n", mc->memc_br0); + return 1; + } + + /* Set parameters for the big flash chip (CS6 or CS0) */ + sbc82xx_flash_map[bigflash].buswidth = 4; + sbc82xx_flash_map[bigflash].size = 0x4000000; + + /* Set parameters for the small flash chip (CS0 or CS6) */ + sbc82xx_flash_map[!bigflash].buswidth = 1; + sbc82xx_flash_map[!bigflash].size = 0x200000; + + /* Set parameters for the user flash chip (CS1) */ + sbc82xx_flash_map[2].buswidth = 4; + sbc82xx_flash_map[2].size = 0x4000000; + + sbc82xx_flash_map[0].phys = mc->memc_br0 & 0xffff8000; + sbc82xx_flash_map[1].phys = mc->memc_br6 & 0xffff8000; + sbc82xx_flash_map[2].phys = mc->memc_br1 & 0xffff8000; + + for (i=0; i<3; i++) { + int8_t flashcs[3] = { 0, 6, 1 }; + int nr_parts; + + printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d", + sbc82xx_flash_map[i].name, sbc82xx_flash_map[i].size >> 20, flashcs[i]); + if (!sbc82xx_flash_map[i].phys) { + /* We know it can't be at zero. */ + printk("): disabled by bootloader.\n"); + continue; + } + printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); + + sbc82xx_flash_map[i].virt = (unsigned long)ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); + + if (!sbc82xx_flash_map[i].virt) { + printk("Failed to ioremap\n"); + continue; + } + + simple_map_init(&sbc82xx_flash_map[i]); + + sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]); + + if (!sbcmtd[i]) + continue; + + sbcmtd[i]->owner = THIS_MODULE; + + nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes, + &sbcmtd_parts[i], 0); + if (nr_parts > 0) { + add_mtd_partitions (sbcmtd[i], sbcmtd_parts[i], nr_parts); + continue; + } + + /* No partitioning detected. Use default */ + if (i == 2) { + add_mtd_device(sbcmtd[i]); + } else if (i == bigflash) { + add_mtd_partitions (sbcmtd[i], bigflash_parts, ARRAY_SIZE(bigflash_parts)); + } else { + add_mtd_partitions (sbcmtd[i], smallflash_parts, ARRAY_SIZE(smallflash_parts)); + } + } + return 0; +} + +static void __exit cleanup_sbc82xx_flash(void) +{ + int i; + + for (i=0; i<3; i++) { + if (!sbcmtd[i]) + continue; + + if (i<2 || sbcmtd_parts[i]) + del_mtd_partitions(sbcmtd[i]); + else + del_mtd_device(sbcmtd[i]); + + kfree(sbcmtd_parts[i]); + map_destroy(sbcmtd[i]); + + iounmap((void *)sbc82xx_flash_map[i].virt); + sbc82xx_flash_map[i].virt = 0; + } +} + +module_init(init_sbc82xx_flash); +module_exit(cleanup_sbc82xx_flash); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse "); +MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II"); diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 707da8106..ab7ee8837 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1315,7 +1315,7 @@ el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) */ static int -netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +netdev_ethtool_ioctl (struct net_device *dev, void __user *useraddr) { u32 ethcmd; struct el3_private *lp = netdev_priv(dev); @@ -1323,7 +1323,7 @@ netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ - if (get_user(ethcmd, (u32 *)useraddr)) + if (get_user(ethcmd, (u32 __user *)useraddr)) return -EFAULT; switch (ethcmd) { @@ -1412,7 +1412,7 @@ netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCETHTOOL: - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + rc = netdev_ethtool_ioctl(dev, rq->ifr_data); break; default: diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index df3240c3c..a3b67aef2 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -287,6 +287,7 @@ struct net_device *__init mc32_probe(int unit) } } + free_netdev(dev); return ERR_PTR(-ENODEV); } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index da9836612..62dd13951 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1546,7 +1546,6 @@ static struct ethtool_ops cp_ethtool_ops = { static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct cp_private *cp = netdev_priv(dev); - struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data; int rc; unsigned long flags; @@ -1554,7 +1553,7 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return -EINVAL; spin_lock_irqsave(&cp->lock, flags); - rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL); + rc = generic_mii_ioctl(&cp->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irqrestore(&cp->lock, flags); return rc; } diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index c4491dab9..7b96c017d 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1571,7 +1571,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. */ -static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr) +static int amd8111e_ethtool_ioctl(struct net_device* dev, void __user *useraddr) { struct amd8111e_priv *lp = netdev_priv(dev); struct pci_dev *pci_dev = lp->pci_dev; @@ -1694,7 +1694,7 @@ static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr) } static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) { - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct mii_ioctl_data *data = if_mii(ifr); struct amd8111e_priv *lp = netdev_priv(dev); int err; u32 mii_regval; @@ -1704,7 +1704,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) switch(cmd) { case SIOCETHTOOL: - return amd8111e_ethtool_ioctl(dev, (void *) ifr->ifr_data); + return amd8111e_ethtool_ioctl(dev, ifr->ifr_data); case SIOCGMIIPHY: data->phy_id = PHY_ID; diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index db21e0c41..925dd0477 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -524,7 +524,7 @@ static void cops_reset(struct net_device *dev, int sleep) static void cops_load (struct net_device *dev) { struct ifreq ifr; - struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data; + struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru; struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; int length, i = 0; diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 8c0a962d5..8bf0bba62 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -259,7 +259,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data; + struct ipddp_route __user *rt = ifr->ifr_data; struct ipddp_route rcp; if(!capable(CAP_NET_ADMIN)) diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 8bd25b970..6b28a3d9b 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -53,25 +53,31 @@ static const char version[] = #ifdef __arm__ static void write_rreg(u_long base, u_int reg, u_int val) { - __asm__("str%?h %1, [%2] @ NET_RAP - str%?h %0, [%2, #-4] @ NET_RDP - " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); + __asm__( + "str%?h %1, [%2] @ NET_RAP\n\t" + "str%?h %0, [%2, #-4] @ NET_RDP" + : + : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); } static inline unsigned short read_rreg(u_long base_addr, u_int reg) { unsigned short v; - __asm__("str%?h %1, [%2] @ NET_RAP - ldr%?h %0, [%2, #-4] @ NET_RDP - " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464)); + __asm__( + "str%?h %1, [%2] @ NET_RAP\n\t" + "ldr%?h %0, [%2, #-4] @ NET_RDP" + : "=r" (v) + : "r" (reg), "r" (ISAIO_BASE + 0x0464)); return v; } static inline void write_ireg(u_long base, u_int reg, u_int val) { - __asm__("str%?h %1, [%2] @ NET_RAP - str%?h %0, [%2, #8] @ NET_IDP - " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); + __asm__( + "str%?h %1, [%2] @ NET_RAP\n\t" + "str%?h %0, [%2, #8] @ NET_IDP" + : + : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); } static inline unsigned short read_ireg(u_long base_addr, u_int reg) @@ -101,16 +107,16 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne } while (length > 8) { unsigned int tmp, tmp2; - __asm__ __volatile__(" - ldm%?ia %1!, {%2, %3} - str%?h %2, [%0], #4 - mov%? %2, %2, lsr #16 - str%?h %2, [%0], #4 - str%?h %3, [%0], #4 - mov%? %3, %3, lsr #16 - str%?h %3, [%0], #4 - " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) - : "0" (offset), "1" (buf)); + __asm__ __volatile__( + "ldm%?ia %1!, {%2, %3}\n\t" + "str%?h %2, [%0], #4\n\t" + "mov%? %2, %2, lsr #16\n\t" + "str%?h %2, [%0], #4\n\t" + "str%?h %3, [%0], #4\n\t" + "mov%? %3, %3, lsr #16\n\t" + "str%?h %3, [%0], #4" + : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) + : "0" (offset), "1" (buf)); length -= 8; } while (length > 0) { @@ -128,36 +134,36 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned length = (length + 1) & ~1; if ((int)buf & 2) { unsigned int tmp; - __asm__ __volatile__(" - ldr%?h %2, [%0], #4 - str%?b %2, [%1], #1 - mov%? %2, %2, lsr #8 - str%?b %2, [%1], #1 - " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); + __asm__ __volatile__( + "ldr%?h %2, [%0], #4\n\t" + "str%?b %2, [%1], #1\n\t" + "mov%? %2, %2, lsr #8\n\t" + "str%?b %2, [%1], #1" + : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); length -= 2; } while (length > 8) { unsigned int tmp, tmp2, tmp3; - __asm__ __volatile__(" - ldr%?h %2, [%0], #4 - ldr%?h %3, [%0], #4 - orr%? %2, %2, %3, lsl #16 - ldr%?h %3, [%0], #4 - ldr%?h %4, [%0], #4 - orr%? %3, %3, %4, lsl #16 - stm%?ia %1!, {%2, %3} - " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) - : "0" (offset), "1" (buf)); + __asm__ __volatile__( + "ldr%?h %2, [%0], #4\n\t" + "ldr%?h %3, [%0], #4\n\t" + "orr%? %2, %2, %3, lsl #16\n\t" + "ldr%?h %3, [%0], #4\n\t" + "ldr%?h %4, [%0], #4\n\t" + "orr%? %3, %3, %4, lsl #16\n\t" + "stm%?ia %1!, {%2, %3}" + : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) + : "0" (offset), "1" (buf)); length -= 8; } while (length > 0) { unsigned int tmp; - __asm__ __volatile__(" - ldr%?h %2, [%0], #4 - str%?b %2, [%1], #1 - mov%? %2, %2, lsr #8 - str%?b %2, [%1], #1 - " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); + __asm__ __volatile__( + "ldr%?h %2, [%0], #4\n\t" + "str%?b %2, [%1], #1\n\t" + "mov%? %2, %2, lsr #8\n\t" + "str%?b %2, [%1], #1" + : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); length -= 2; } } @@ -618,6 +624,7 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status & CSR0_CERR) { handled = 1; mod_timer(&priv->timer, jiffies); + } } while (--n && status & (CSR0_RINT | CSR0_TINT)); return IRQ_RETVAL(handled); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 7543bfbac..9981968a8 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -242,7 +242,7 @@ static void cleanup_card(struct net_device *dev) { #ifdef CONFIG_MCA struct net_local *lp = netdev_priv(dev); - if (lp->mca_slot) + if (lp->mca_slot >= 0) mca_mark_as_unused(lp->mca_slot); #endif free_irq(dev->irq, NULL); @@ -444,11 +444,11 @@ found: break; } if (i == 8) { - goto err_out; + goto err_mca; } } else { if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr) - goto err_out; + goto err_mca; irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03]; } } @@ -546,11 +546,16 @@ found: if (ret) { printk (" AT1700 at %#3x is unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); - goto err_out; + goto err_mca; } return 0; +err_mca: +#ifdef CONFIG_MCA + if (slot >= 0) + mca_mark_as_unused(slot); +#endif err_out: #ifndef CONFIG_X86_PC9800 release_region(ioaddr, AT1700_IO_EXTENT); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 2bd0ac959..afcdcffc7 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1269,7 +1269,7 @@ static void set_rx_mode(struct net_device *dev) static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; /* fixme */ switch(cmd) { diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 778fd0754..6e57c1434 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1103,7 +1103,7 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); - mii = (struct mii_ioctl_data *)&ifr.ifr_data; + mii = if_mii(&ifr); if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { @@ -2357,10 +2357,10 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr) { struct ethtool_drvinfo info; - void *addr = ifr->ifr_data; + void __user *addr = ifr->ifr_data; uint32_t cmd; - if (get_user(cmd, (uint32_t *)addr)) { + if (get_user(cmd, (uint32_t __user *)addr)) { return -EFAULT; } @@ -3667,8 +3667,10 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) { struct net_device *slave_dev = NULL; - struct ifbond *u_binfo = NULL, k_binfo; - struct ifslave *u_sinfo = NULL, k_sinfo; + struct ifbond k_binfo; + struct ifbond __user *u_binfo = NULL; + struct ifslave k_sinfo; + struct ifslave __user *u_sinfo = NULL; struct mii_ioctl_data *mii = NULL; int prev_abi_ver = orig_app_abi_ver; int res = 0; @@ -3680,7 +3682,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd case SIOCETHTOOL: return bond_ethtool_ioctl(bond_dev, ifr); case SIOCGMIIPHY: - mii = (struct mii_ioctl_data *)&ifr->ifr_data; + mii = if_mii(ifr); if (!mii) { return -EINVAL; } @@ -3691,7 +3693,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd * We do this again just in case we were called by SIOCGMIIREG * instead of SIOCGMIIPHY. */ - mii = (struct mii_ioctl_data *)&ifr->ifr_data; + mii = if_mii(ifr); if (!mii) { return -EINVAL; } @@ -3711,7 +3713,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd return 0; case BOND_INFO_QUERY_OLD: case SIOCBONDINFOQUERY: - u_binfo = (struct ifbond *)ifr->ifr_data; + u_binfo = (struct ifbond __user *)ifr->ifr_data; if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { return -EFAULT; @@ -3727,7 +3729,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd return res; case BOND_SLAVE_INFO_QUERY_OLD: case SIOCBONDSLAVEINFOQUERY: - u_sinfo = (struct ifslave *)ifr->ifr_data; + u_sinfo = (struct ifslave __user *)ifr->ifr_data; if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { return -EFAULT; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 80e8617dc..5d62a032b 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1937,7 +1937,7 @@ static void depca_dbg_open(struct net_device *dev) static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct depca_private *lp = (struct depca_private *) dev->priv; - struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data; + struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru; int i, status = 0; u_long ioaddr = dev->base_addr; union { diff --git a/drivers/net/depca.h b/drivers/net/depca.h index 2fa155843..11785275a 100644 --- a/drivers/net/depca.h +++ b/drivers/net/depca.h @@ -162,7 +162,7 @@ struct depca_ioctl { unsigned short cmd; /* Command to run */ unsigned short len; /* Length of the data buffer */ - unsigned char *data; /* Pointer to the data buffer */ + unsigned char __user *data; /* Pointer to the data buffer */ }; /* diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4673bd829..39cabaf80 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -107,7 +107,7 @@ static int change_mtu (struct net_device *dev, int new_mtu); static void set_multicast (struct net_device *dev); static struct net_device_stats *get_stats (struct net_device *dev); static int clear_stats (struct net_device *dev); -static int rio_ethtool_ioctl (struct net_device *dev, void *useraddr); +static int rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr); static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int rio_close (struct net_device *dev); static int find_miiphy (struct net_device *dev); @@ -1195,7 +1195,7 @@ set_multicast (struct net_device *dev) } static int -rio_ethtool_ioctl (struct net_device *dev, void *useraddr) +rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr) { struct netdev_private *np = dev->priv; u32 ethcmd; @@ -1325,7 +1325,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { int phy_addr; struct netdev_private *np = dev->priv; - struct mii_data *miidata = (struct mii_data *) &rq->ifr_data; + struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru; struct netdev_desc *desc; int i; @@ -1333,7 +1333,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) phy_addr = np->phy_addr; switch (cmd) { case SIOCETHTOOL: - return rio_ethtool_ioctl (dev, (void *) rq->ifr_data); + return rio_ethtool_ioctl(dev, rq->ifr_data); case SIOCDEVPRIVATE: break; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index cf7ae0569..64e4aeb63 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -66,12 +66,15 @@ LK1.1.14 (Kryzsztof Halasa): * fix spurious bad initializations * pound phy a la SMSC's app note on the subject + + AC1.1.14ac + * fix power up/down for ethtool that broke in 1.11 */ #define DRV_NAME "epic100" -#define DRV_VERSION "1.11+LK1.1.14" -#define DRV_RELDATE "Aug 4, 2002" +#define DRV_VERSION "1.11+LK1.1.14+AC1.1.14" +#define DRV_RELDATE "June 2, 2004" /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -1424,6 +1427,27 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value) debug = value; } +static int ethtool_begin(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + /* power-up, if interface is down */ + if (! netif_running(dev)) { + outl(0x0200, ioaddr + GENCTL); + outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + } + return 0; +} + +static void ethtool_complete(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + /* power-down, if interface is down */ + if (! netif_running(dev)) { + outl(0x0008, ioaddr + GENCTL); + outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); + } +} + static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -1434,13 +1458,15 @@ static struct ethtool_ops netdev_ethtool_ops = { .set_msglevel = netdev_set_msglevel, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .begin = ethtool_begin, + .complete = ethtool_complete }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct epic_private *np = dev->priv; long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); int rc; /* power-up, if interface is down */ diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 0ee18be4a..816534011 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -255,14 +255,14 @@ static int eql_close(struct net_device *dev) return 0; } -static int eql_enslave(struct net_device *dev, slaving_request_t *srq); -static int eql_emancipate(struct net_device *dev, slaving_request_t *srq); +static int eql_enslave(struct net_device *dev, slaving_request_t __user *srq); +static int eql_emancipate(struct net_device *dev, slaving_request_t __user *srq); -static int eql_g_slave_cfg(struct net_device *dev, slave_config_t *sc); -static int eql_s_slave_cfg(struct net_device *dev, slave_config_t *sc); +static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *sc); +static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *sc); -static int eql_g_master_cfg(struct net_device *dev, master_config_t *mc); -static int eql_s_master_cfg(struct net_device *dev, master_config_t *mc); +static int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mc); +static int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mc); static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -272,23 +272,17 @@ static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case EQL_ENSLAVE: - return eql_enslave(dev, - (slaving_request_t *) ifr->ifr_data); + return eql_enslave(dev, ifr->ifr_data); case EQL_EMANCIPATE: - return eql_emancipate(dev, - (slaving_request_t *) ifr->ifr_data); + return eql_emancipate(dev, ifr->ifr_data); case EQL_GETSLAVECFG: - return eql_g_slave_cfg(dev, - (slave_config_t *) ifr->ifr_data); + return eql_g_slave_cfg(dev, ifr->ifr_data); case EQL_SETSLAVECFG: - return eql_s_slave_cfg(dev, - (slave_config_t *) ifr->ifr_data); + return eql_s_slave_cfg(dev, ifr->ifr_data); case EQL_GETMASTRCFG: - return eql_g_master_cfg(dev, - (master_config_t *) ifr->ifr_data); + return eql_g_master_cfg(dev, ifr->ifr_data); case EQL_SETMASTRCFG: - return eql_s_master_cfg(dev, - (master_config_t *) ifr->ifr_data); + return eql_s_master_cfg(dev, ifr->ifr_data); default: return -EOPNOTSUPP; }; @@ -411,7 +405,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) return -ENOSPC; } -static int eql_enslave(struct net_device *master_dev, slaving_request_t *srqp) +static int eql_enslave(struct net_device *master_dev, slaving_request_t __user *srqp) { struct net_device *slave_dev; slaving_request_t srq; @@ -457,7 +451,7 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t *srqp) return -EINVAL; } -static int eql_emancipate(struct net_device *master_dev, slaving_request_t *srqp) +static int eql_emancipate(struct net_device *master_dev, slaving_request_t __user *srqp) { equalizer_t *eql = master_dev->priv; struct net_device *slave_dev; @@ -489,7 +483,7 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t *srqp return ret; } -static int eql_g_slave_cfg(struct net_device *dev, slave_config_t *scp) +static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) { equalizer_t *eql = dev->priv; slave_t *slave; @@ -522,7 +516,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t *scp) return ret; } -static int eql_s_slave_cfg(struct net_device *dev, slave_config_t *scp) +static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) { slave_t *slave; equalizer_t *eql; @@ -553,7 +547,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t *scp) return ret; } -static int eql_g_master_cfg(struct net_device *dev, master_config_t *mcp) +static int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mcp) { equalizer_t *eql; master_config_t mc; @@ -569,7 +563,7 @@ static int eql_g_master_cfg(struct net_device *dev, master_config_t *mcp) return -EINVAL; } -static int eql_s_master_cfg(struct net_device *dev, master_config_t *mcp) +static int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mcp) { equalizer_t *eql; master_config_t mc; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 3bf22730e..eb9f346d1 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1518,13 +1518,13 @@ static int __init EISA_signature(char *name, s32 eisa_id) return status; /* return the device name string */ } -static int ewrk3_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int ewrk3_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; u_long iobase = dev->base_addr; u32 ethcmd; - if (get_user(ethcmd, (u32 *)useraddr)) + if (get_user(ethcmd, (u32 __user *)useraddr)) return -EFAULT; switch (ethcmd) { @@ -1707,7 +1707,7 @@ static int ewrk3_ethtool_ioctl(struct net_device *dev, void *useraddr) static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; - struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data; + struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru; u_long iobase = dev->base_addr; int i, j, status = 0; u_char csr; @@ -1721,7 +1721,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* ethtool IOCTLs are handled elsewhere */ if (cmd == SIOCETHTOOL) - return ewrk3_ethtool_ioctl(dev, (void *)rq->ifr_data); + return ewrk3_ethtool_ioctl(dev, rq->ifr_data); /* Other than ethtool, all we handle are private IOCTLs */ if (cmd != EWRK3IOCTL) diff --git a/drivers/net/ewrk3.h b/drivers/net/ewrk3.h index 46ec00996..fb74bd053 100644 --- a/drivers/net/ewrk3.h +++ b/drivers/net/ewrk3.h @@ -296,7 +296,7 @@ struct ewrk3_ioctl { unsigned short cmd; /* Command to run */ unsigned short len; /* Length of the data buffer */ - unsigned char *data; /* Pointer to the data buffer */ + unsigned char __user *data; /* Pointer to the data buffer */ }; /* diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 73dcb6883..503e8f6c9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -556,7 +556,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) return &np->stats; } -static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int nv_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); @@ -634,7 +634,7 @@ static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { switch(cmd) { case SIOCETHTOOL: - return nv_ethtool_ioctl(dev, (void *) rq->ifr_data); + return nv_ethtool_ioctl(dev, rq->ifr_data); default: return -EOPNOTSUPP; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 2089b1a1e..f1ec80665 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1869,7 +1869,7 @@ static void set_rx_mode(struct net_device *dev) } } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct hamachi_private *np = dev->priv; u32 ethcmd; @@ -1937,17 +1937,17 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct hamachi_private *np = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); int rc; if (!netif_running(dev)) return -EINVAL; if (cmd == SIOCETHTOOL) - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + rc = netdev_ethtool_ioctl(dev, rq->ifr_data); else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */ - u32 *d = (u32 *)&rq->ifr_data; + u32 *d = (u32 *)&rq->ifr_ifru; /* Should add this check here or an ordinary user can do nasty * things. -KDU * diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index d5b7fd96f..d5b7db1bd 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1166,8 +1166,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; - if (get_user(cmd, (int *)ifr->ifr_data)) - return -EFAULT; if (copy_from_user(&hi, ifr->ifr_data, sizeof(hi))) return -EFAULT; diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 28e9da3db..4bd7c0965 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -414,7 +414,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, { struct baycom_state *bc; struct baycom_ioctl bi; - int cmd2; if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { @@ -425,8 +424,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; - if (get_user(cmd2, (int *)ifr->ifr_data)) - return -EFAULT; switch (hi->cmd) { default: break; diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 2dc64f049..5c6257ee5 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -529,7 +529,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, { struct baycom_state *bc; struct baycom_ioctl bi; - int cmd2; if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { @@ -540,8 +539,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; - if (get_user(cmd2, (int *)ifr->ifr_data)) - return -EFAULT; switch (hi->cmd) { default: break; diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index f288c9241..4aef97039 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -569,7 +569,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, { struct baycom_state *bc; struct baycom_ioctl bi; - int cmd2; if (!dev || !dev->priv || ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { @@ -580,8 +579,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; - if (get_user(cmd2, (int *)ifr->ifr_data)) - return -EFAULT; switch (hi->cmd) { default: break; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index fda187222..6b85ab3c9 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -331,7 +331,7 @@ static int bpq_set_mac_address(struct net_device *dev, void *addr) */ static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct bpq_ethaddr *ethaddr = (struct bpq_ethaddr *)ifr->ifr_data; + struct bpq_ethaddr __user *ethaddr = ifr->ifr_data; struct bpqdev *bpq = dev->priv; struct bpq_req req; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 0e6844fc3..f7fc3b9c0 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1714,13 +1714,11 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct scc_mem_config memcfg; struct scc_hw_config hwcfg; struct scc_calibrate cal; - struct scc_channel *scc; + struct scc_channel *scc = (struct scc_channel *) dev->priv; int chan; unsigned char device_name[IFNAMSIZ]; - void *arg; + void __user *arg = ifr->ifr_data; - scc = (struct scc_channel *) dev->priv; - arg = (void *) ifr->ifr_data; if (!Driver_Initialized) { diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h new file mode 100644 index 000000000..5310033ad --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -0,0 +1,263 @@ +/* + * ibm_emac.h + * + * + * Armin Kuster akuster@mvista.com + * June, 2002 + * + * Copyright 2002 MontaVista Softare Inc. + * + * 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. + */ + +#ifndef _IBM_EMAC_H_ +#define _IBM_EMAC_H_ +/* General defines needed for the driver */ + +/* Emac */ +typedef struct emac_regs { + u32 em0mr0; + u32 em0mr1; + u32 em0tmr0; + u32 em0tmr1; + u32 em0rmr; + u32 em0isr; + u32 em0iser; + u32 em0iahr; + u32 em0ialr; + u32 em0vtpid; + u32 em0vtci; + u32 em0ptr; + u32 em0iaht1; + u32 em0iaht2; + u32 em0iaht3; + u32 em0iaht4; + u32 em0gaht1; + u32 em0gaht2; + u32 em0gaht3; + u32 em0gaht4; + u32 em0lsah; + u32 em0lsal; + u32 em0ipgvr; + u32 em0stacr; + u32 em0trtr; + u32 em0rwmr; +} emac_t; + +/* MODE REG 0 */ +#define EMAC_M0_RXI 0x80000000 +#define EMAC_M0_TXI 0x40000000 +#define EMAC_M0_SRST 0x20000000 +#define EMAC_M0_TXE 0x10000000 +#define EMAC_M0_RXE 0x08000000 +#define EMAC_M0_WKE 0x04000000 + +/* MODE Reg 1 */ +#define EMAC_M1_FDE 0x80000000 +#define EMAC_M1_ILE 0x40000000 +#define EMAC_M1_VLE 0x20000000 +#define EMAC_M1_EIFC 0x10000000 +#define EMAC_M1_APP 0x08000000 +#define EMAC_M1_AEMI 0x02000000 +#define EMAC_M1_IST 0x01000000 +#define EMAC_M1_MF_1000GPCS 0x00c00000 /* Internal GPCS */ +#define EMAC_M1_MF_1000MBPS 0x00800000 /* External GPCS */ +#define EMAC_M1_MF_100MBPS 0x00400000 +#define EMAC_M1_RFS_16K 0x00280000 /* 000 for 512 byte */ +#define EMAC_M1_TR 0x00008000 +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_M1_RFS_8K 0x00200000 +#define EMAC_M1_RFS_4K 0x00180000 +#define EMAC_M1_RFS_2K 0x00100000 +#define EMAC_M1_RFS_1K 0x00080000 +#define EMAC_M1_TX_FIFO_16K 0x00050000 /* 0's for 512 byte */ +#define EMAC_M1_TX_FIFO_8K 0x00040000 +#define EMAC_M1_TX_FIFO_4K 0x00030000 +#define EMAC_M1_TX_FIFO_2K 0x00020000 +#define EMAC_M1_TX_FIFO_1K 0x00010000 +#define EMAC_M1_TX_TR 0x00008000 +#define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */ +#define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */ +#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */ +#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */ +#define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */ +#define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */ +#else /* CONFIG_IBM_EMAC4 */ +#define EMAC_M1_RFS_4K 0x00300000 /* ~4k for 512 byte */ +#define EMAC_M1_RFS_2K 0x00200000 +#define EMAC_M1_RFS_1K 0x00100000 +#define EMAC_M1_TX_FIFO_2K 0x00080000 /* 0's for 512 byte */ +#define EMAC_M1_TX_FIFO_1K 0x00040000 +#define EMAC_M1_TR0_DEPEND 0x00010000 /* 0'x for single packet */ +#define EMAC_M1_TR1_DEPEND 0x00004000 +#define EMAC_M1_TR1_MULTI 0x00002000 +#define EMAC_M1_JUMBO_ENABLE 0x00001000 +#endif /* CONFIG_IBM_EMAC4 */ +#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \ + EMAC_M1_APP | \ + EMAC_M1_TR) + +/* Transmit Mode Register 0 */ +#define EMAC_TMR0_GNP0 0x80000000 +#define EMAC_TMR0_GNP1 0x40000000 +#define EMAC_TMR0_GNPD 0x20000000 +#define EMAC_TMR0_FC 0x10000000 +#define EMAC_TMR0_TFAE_2_32 0x00000001 +#define EMAC_TMR0_TFAE_4_64 0x00000002 +#define EMAC_TMR0_TFAE_8_128 0x00000003 +#define EMAC_TMR0_TFAE_16_256 0x00000004 +#define EMAC_TMR0_TFAE_32_512 0x00000005 +#define EMAC_TMR0_TFAE_64_1024 0x00000006 +#define EMAC_TMR0_TFAE_128_2048 0x00000007 + +/* Receive Mode Register */ +#define EMAC_RMR_SP 0x80000000 +#define EMAC_RMR_SFCS 0x40000000 +#define EMAC_RMR_ARRP 0x20000000 +#define EMAC_RMR_ARP 0x10000000 +#define EMAC_RMR_AROP 0x08000000 +#define EMAC_RMR_ARPI 0x04000000 +#define EMAC_RMR_PPP 0x02000000 +#define EMAC_RMR_PME 0x01000000 +#define EMAC_RMR_PMME 0x00800000 +#define EMAC_RMR_IAE 0x00400000 +#define EMAC_RMR_MIAE 0x00200000 +#define EMAC_RMR_BAE 0x00100000 +#define EMAC_RMR_MAE 0x00080000 +#define EMAC_RMR_RFAF_2_32 0x00000001 +#define EMAC_RMR_RFAF_4_64 0x00000002 +#define EMAC_RMR_RFAF_8_128 0x00000003 +#define EMAC_RMR_RFAF_16_256 0x00000004 +#define EMAC_RMR_RFAF_32_512 0x00000005 +#define EMAC_RMR_RFAF_64_1024 0x00000006 +#define EMAC_RMR_RFAF_128_2048 0x00000007 +#define EMAC_RMR_BASE (EMAC_RMR_IAE | EMAC_RMR_BAE) + +/* Interrupt Status & enable Regs */ +#define EMAC_ISR_OVR 0x02000000 +#define EMAC_ISR_PP 0x01000000 +#define EMAC_ISR_BP 0x00800000 +#define EMAC_ISR_RP 0x00400000 +#define EMAC_ISR_SE 0x00200000 +#define EMAC_ISR_ALE 0x00100000 +#define EMAC_ISR_BFCS 0x00080000 +#define EMAC_ISR_PTLE 0x00040000 +#define EMAC_ISR_ORE 0x00020000 +#define EMAC_ISR_IRE 0x00010000 +#define EMAC_ISR_DBDM 0x00000200 +#define EMAC_ISR_DB0 0x00000100 +#define EMAC_ISR_SE0 0x00000080 +#define EMAC_ISR_TE0 0x00000040 +#define EMAC_ISR_DB1 0x00000020 +#define EMAC_ISR_SE1 0x00000010 +#define EMAC_ISR_TE1 0x00000008 +#define EMAC_ISR_MOS 0x00000002 +#define EMAC_ISR_MOF 0x00000001 + +/* STA CONTROL REG */ +#define EMAC_STACR_OC 0x00008000 +#define EMAC_STACR_PHYE 0x00004000 +#define EMAC_STACR_WRITE 0x00002000 +#define EMAC_STACR_READ 0x00001000 +#define EMAC_STACR_CLK_83MHZ 0x00000800 /* 0's for 50Mhz */ +#define EMAC_STACR_CLK_66MHZ 0x00000400 +#define EMAC_STACR_CLK_100MHZ 0x00000C00 + +/* Transmit Request Threshold Register */ +#define EMAC_TRTR_1600 0x18000000 /* 0's for 64 Bytes */ +#define EMAC_TRTR_1024 0x0f000000 +#define EMAC_TRTR_512 0x07000000 +#define EMAC_TRTR_256 0x03000000 +#define EMAC_TRTR_192 0x10000000 +#define EMAC_TRTR_128 0x01000000 + +#define EMAC_TX_CTRL_GFCS 0x0200 +#define EMAC_TX_CTRL_GP 0x0100 +#define EMAC_TX_CTRL_ISA 0x0080 +#define EMAC_TX_CTRL_RSA 0x0040 +#define EMAC_TX_CTRL_IVT 0x0020 +#define EMAC_TX_CTRL_RVT 0x0010 +#define EMAC_TX_CTRL_TAH_CSUM 0x000e /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG4 0x000a /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG3 0x0008 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG2 0x0006 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG1 0x0004 /* TAH only */ +#define EMAC_TX_CTRL_TAH_SEG0 0x0002 /* TAH only */ +#define EMAC_TX_CTRL_TAH_DIS 0x0000 /* TAH only */ + +#define EMAC_TX_CTRL_DFLT ( \ + MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP ) + +/* madmal transmit status / Control bits */ +#define EMAC_TX_ST_BFCS 0x0200 +#define EMAC_TX_ST_BPP 0x0100 +#define EMAC_TX_ST_LCS 0x0080 +#define EMAC_TX_ST_ED 0x0040 +#define EMAC_TX_ST_EC 0x0020 +#define EMAC_TX_ST_LC 0x0010 +#define EMAC_TX_ST_MC 0x0008 +#define EMAC_TX_ST_SC 0x0004 +#define EMAC_TX_ST_UR 0x0002 +#define EMAC_TX_ST_SQE 0x0001 + +/* madmal receive status / Control bits */ +#define EMAC_RX_ST_OE 0x0200 +#define EMAC_RX_ST_PP 0x0100 +#define EMAC_RX_ST_BP 0x0080 +#define EMAC_RX_ST_RP 0x0040 +#define EMAC_RX_ST_SE 0x0020 +#define EMAC_RX_ST_AE 0x0010 +#define EMAC_RX_ST_BFCS 0x0008 +#define EMAC_RX_ST_PTL 0x0004 +#define EMAC_RX_ST_ORE 0x0002 +#define EMAC_RX_ST_IRE 0x0001 +#define EMAC_BAD_RX_PACKET 0x02ff +#define EMAC_CSUM_VER_ERROR 0x0003 + +/* identify a bad rx packet dependent on emac features */ +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_IS_BAD_RX_PACKET(desc) \ + (((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \ + ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \ + ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE))) +#else +#define EMAC_IS_BAD_RX_PACKET(desc) \ + (desc & EMAC_BAD_RX_PACKET) +#endif + +/* Revision specific EMAC register defaults */ +#ifdef CONFIG_IBM_EMAC4 +#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ + EMAC_M1_OPB_CLK_83 | \ + EMAC_M1_TX_MWSW) +#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ + EMAC_RMR_RFAF_128_2048) +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ + EMAC_TMR0_TFAE_128_2048) +#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 +#else /* !CONFIG_IBM_EMAC4 */ +#define EMAC_M1_DEFAULT EMAC_M1_BASE +#define EMAC_RMR_DEFAULT EMAC_RMR_BASE +#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0 +#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 +#endif /* CONFIG_IBM_EMAC4 */ + +/* SoC implementation specific EMAC register defaults */ +#if defined(CONFIG_440GP) +#define EMAC_RWMR_DEFAULT 0x80009000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0xf8640000 +#elif defined(CONFIG_440GX) +#define EMAC_RWMR_DEFAULT 0x1000a200 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 +#define EMAC_TMR1_DEFAULT 0x88810000 +#else +#define EMAC_RWMR_DEFAULT 0x0f002000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC_TMR1_DEFAULT 0x380f0000 +#endif /* CONFIG_440GP */ + +#endif diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 0bc7f8242..2ca3de076 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1556,7 +1556,7 @@ static struct ethtool_ops emac_ethtool_ops = { static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct ocp_enet_private *fep = dev->priv; - uint *data = (uint *) & rq->ifr_data; + uint *data = (uint *) & rq->ifr_ifru; switch (cmd) { case SIOCGMIIPHY: diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h new file mode 100644 index 000000000..691ce4e5c --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -0,0 +1,146 @@ +/* + * ibm_emac_core.h + * + * Ethernet driver for the built in ethernet on the IBM 405 PowerPC + * processor. + * + * Armin Kuster akuster@mvista.com + * Sept, 2001 + * + * Orignial driver + * Johnnie Peters + * jpeters@mvista.com + * + * Copyright 2000 MontaVista Softare Inc. + * + * 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. + */ + +#ifndef _IBM_EMAC_CORE_H_ +#define _IBM_EMAC_CORE_H_ + +#include +#include +#include /* For phys_addr_t */ + +#include "ibm_emac.h" +#include "ibm_emac_phy.h" +#include "ibm_emac_rgmii.h" +#include "ibm_emac_zmii.h" +#include "ibm_emac_mal.h" +#include "ibm_emac_tah.h" + +#ifndef CONFIG_IBM_EMAC_TXB +#define NUM_TX_BUFF 64 +#define NUM_RX_BUFF 64 +#else +#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB +#endif + +/* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ +#ifndef CONFIG_IBM_EMAC_SKBRES +#define SKB_RES 2 +#else +#define SKB_RES CONFIG_IBM_EMAC_SKBRES +#endif + +/* Note about alignement. alloc_skb() returns a cache line + * aligned buffer. However, dev_alloc_skb() will add 16 more + * bytes and "reserve" them, so our buffer will actually end + * on a half cache line. What we do is to use directly + * alloc_skb, allocate 16 more bytes to match the total amount + * allocated by dev_alloc_skb(), but we don't reserve. + */ +#define MAX_NUM_BUF_DESC 255 +#define DESC_BUF_SIZE 4080 /* max 4096-16 */ +#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16) + +/* Transmitter timeout. */ +#define TX_TIMEOUT (2*HZ) + +/* MDIO latency delay */ +#define MDIO_DELAY 50 + +/* Power managment shift registers */ +#define IBM_CPM_EMMII 0 /* Shift value for MII */ +#define IBM_CPM_EMRX 1 /* Shift value for recv */ +#define IBM_CPM_EMTX 2 /* Shift value for MAC */ +#define IBM_CPM_EMAC(x) (((x)>>IBM_CPM_EMMII) | ((x)>>IBM_CPM_EMRX) | ((x)>>IBM_CPM_EMTX)) + +#define ENET_HEADER_SIZE 14 +#define ENET_FCS_SIZE 4 +#define ENET_DEF_MTU_SIZE 1500 +#define ENET_DEF_BUF_SIZE (ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE) +#define EMAC_MIN_FRAME 64 +#define EMAC_MAX_FRAME 9018 +#define EMAC_MIN_MTU (EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) +#define EMAC_MAX_MTU (EMAC_MAX_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) + +#ifdef CONFIG_IBM_EMAC_ERRMSG +void emac_serr_dump_0(struct net_device *dev); +void emac_serr_dump_1(struct net_device *dev); +void emac_err_dump(struct net_device *dev, int em0isr); +void emac_phy_dump(struct net_device *); +void emac_desc_dump(struct net_device *); +void emac_mac_dump(struct net_device *); +void emac_mal_dump(struct net_device *); +#else +#define emac_serr_dump_0(dev) do { } while (0) +#define emac_serr_dump_1(dev) do { } while (0) +#define emac_err_dump(dev,x) do { } while (0) +#define emac_phy_dump(dev) do { } while (0) +#define emac_desc_dump(dev) do { } while (0) +#define emac_mac_dump(dev) do { } while (0) +#define emac_mal_dump(dev) do { } while (0) +#endif + +struct ocp_enet_private { + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; + struct mal_descriptor *tx_desc; + struct mal_descriptor *rx_desc; + struct mal_descriptor *rx_dirty; + struct net_device_stats stats; + int tx_cnt; + int rx_slot; + int dirty_rx; + int tx_slot; + int ack_slot; + int rx_buffer_size; + + struct mii_phy phy_mii; + int mii_phy_addr; + int want_autoneg; + int timer_ticks; + struct timer_list link_timer; + struct net_device *mdio_dev; + + struct ocp_device *rgmii_dev; + int rgmii_input; + + struct ocp_device *zmii_dev; + int zmii_input; + + struct ibm_ocp_mal *mal; + int mal_tx_chan, mal_rx_chan; + struct mal_commac commac; + + struct ocp_device *tah_dev; + + int opened; + int going_away; + int wol_irq; + emac_t *emacp; + struct ocp_device *ocpdev; + struct net_device *ndev; + spinlock_t lock; +}; +#endif /* _IBM_EMAC_CORE_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c new file mode 100644 index 000000000..c8512046c --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -0,0 +1,224 @@ +/* + * ibm_ocp_debug.c + * + * This has all the debug routines that where in *_enet.c + * + * Armin Kuster akuster@mvista.com + * April , 2002 + * + * Copyright 2002 MontaVista Softare Inc. + * + * 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 +#include "ibm_ocp_mal.h" +#include "ibm_ocp_zmii.h" +#include "ibm_ocp_enet.h" + +extern int emac_phy_read(struct net_device *dev, int mii_id, int reg); + +void emac_phy_dump(struct net_device *dev) +{ + struct ocp_enet_private *fep = dev->priv; + unsigned long i; + uint data; + + printk(KERN_DEBUG " Prepare for Phy dump....\n"); + for (i = 0; i < 0x1A; i++) { + data = emac_phy_read(dev, fep->mii_phy_addr, i); + printk(KERN_DEBUG "Phy reg 0x%lx ==> %4x\n", i, data); + if (i == 0x07) + i = 0x0f; + } +} + +void emac_desc_dump(struct net_device *dev) +{ + struct ocp_enet_private *fep = dev->priv; + int curr_slot; + + printk(KERN_DEBUG + "dumping the receive descriptors: current slot is %d\n", + fep->rx_slot); + for (curr_slot = 0; curr_slot < NUM_RX_BUFF; curr_slot++) { + printk(KERN_DEBUG + "Desc %02d: status 0x%04x, length %3d, addr 0x%x\n", + curr_slot, fep->rx_desc[curr_slot].ctrl, + fep->rx_desc[curr_slot].data_len, + (unsigned int)fep->rx_desc[curr_slot].data_ptr); + } +} + +void emac_mac_dump(struct net_device *dev) +{ + struct ocp_enet_private *fep = dev->priv; + volatile emac_t *emacp = fep->emacp; + + printk(KERN_DEBUG "EMAC DEBUG ********** \n"); + printk(KERN_DEBUG "EMAC_M0 ==> 0x%x\n", in_be32(&emacp->em0mr0)); + printk(KERN_DEBUG "EMAC_M1 ==> 0x%x\n", in_be32(&emacp->em0mr1)); + printk(KERN_DEBUG "EMAC_TXM0==> 0x%x\n", in_be32(&emacp->em0tmr0)); + printk(KERN_DEBUG "EMAC_TXM1==> 0x%x\n", in_be32(&emacp->em0tmr1)); + printk(KERN_DEBUG "EMAC_RXM ==> 0x%x\n", in_be32(&emacp->em0rmr)); + printk(KERN_DEBUG "EMAC_ISR ==> 0x%x\n", in_be32(&emacp->em0isr)); + printk(KERN_DEBUG "EMAC_IER ==> 0x%x\n", in_be32(&emacp->em0iser)); + printk(KERN_DEBUG "EMAC_IAH ==> 0x%x\n", in_be32(&emacp->em0iahr)); + printk(KERN_DEBUG "EMAC_IAL ==> 0x%x\n", in_be32(&emacp->em0ialr)); + printk(KERN_DEBUG "EMAC_VLAN_TPID_REG ==> 0x%x\n", + in_be32(&emacp->em0vtpid)); +} + +void emac_mal_dump(struct net_device *dev) +{ + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + + printk(KERN_DEBUG " MAL DEBUG ********** \n"); + printk(KERN_DEBUG " MCR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALCR)); + printk(KERN_DEBUG " ESR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALESR)); + printk(KERN_DEBUG " IER ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALIER)); +#ifdef CONFIG_40x + printk(KERN_DEBUG " DBR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALDBR)); +#endif /* CONFIG_40x */ + printk(KERN_DEBUG " TXCASR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCASR)); + printk(KERN_DEBUG " TXCARR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCARR)); + printk(KERN_DEBUG " TXEOBISR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXEOBISR)); + printk(KERN_DEBUG " TXDEIR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXDEIR)); + printk(KERN_DEBUG " RXCASR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCASR)); + printk(KERN_DEBUG " RXCARR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCARR)); + printk(KERN_DEBUG " RXEOBISR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXEOBISR)); + printk(KERN_DEBUG " RXDEIR ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXDEIR)); + printk(KERN_DEBUG " TXCTP0R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP0R)); + printk(KERN_DEBUG " TXCTP1R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP1R)); + printk(KERN_DEBUG " TXCTP2R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP2R)); + printk(KERN_DEBUG " TXCTP3R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP3R)); + printk(KERN_DEBUG " RXCTP0R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP0R)); + printk(KERN_DEBUG " RXCTP1R ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP1R)); + printk(KERN_DEBUG " RCBS0 ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS0)); + printk(KERN_DEBUG " RCBS1 ==> 0x%x\n", + (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS1)); +} + +void emac_serr_dump_0(struct net_device *dev) +{ + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + unsigned long int mal_error, plb_error, plb_addr; + + mal_error = get_mal_dcrn(mal, DCRN_MALESR); + printk(KERN_DEBUG "ppc405_eth_serr: %s channel %ld \n", + (mal_error & 0x40000000) ? "Receive" : + "Transmit", (mal_error & 0x3e000000) >> 25); + printk(KERN_DEBUG " ----- latched error -----\n"); + if (mal_error & MALESR_DE) + printk(KERN_DEBUG " DE: descriptor error\n"); + if (mal_error & MALESR_OEN) + printk(KERN_DEBUG " ONE: OPB non-fullword error\n"); + if (mal_error & MALESR_OTE) + printk(KERN_DEBUG " OTE: OPB timeout error\n"); + if (mal_error & MALESR_OSE) + printk(KERN_DEBUG " OSE: OPB slave error\n"); + + if (mal_error & MALESR_PEIN) { + plb_error = mfdcr(DCRN_PLB0_BESR); + printk(KERN_DEBUG + " PEIN: PLB error, PLB0_BESR is 0x%x\n", + (unsigned int)plb_error); + plb_addr = mfdcr(DCRN_PLB0_BEAR); + printk(KERN_DEBUG + " PEIN: PLB error, PLB0_BEAR is 0x%x\n", + (unsigned int)plb_addr); + } +} + +void emac_serr_dump_1(struct net_device *dev) +{ + struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; + int mal_error = get_mal_dcrn(mal, DCRN_MALESR); + + printk(KERN_DEBUG " ----- cumulative errors -----\n"); + if (mal_error & MALESR_DEI) + printk(KERN_DEBUG " DEI: descriptor error interrupt\n"); + if (mal_error & MALESR_ONEI) + printk(KERN_DEBUG " OPB non-fullword error interrupt\n"); + if (mal_error & MALESR_OTEI) + printk(KERN_DEBUG " OTEI: timeout error interrupt\n"); + if (mal_error & MALESR_OSEI) + printk(KERN_DEBUG " OSEI: slave error interrupt\n"); + if (mal_error & MALESR_PBEI) + printk(KERN_DEBUG " PBEI: PLB bus error interrupt\n"); +} + +void emac_err_dump(struct net_device *dev, int em0isr) +{ + printk(KERN_DEBUG "%s: on-chip ethernet error:\n", dev->name); + + if (em0isr & EMAC_ISR_OVR) + printk(KERN_DEBUG " OVR: overrun\n"); + if (em0isr & EMAC_ISR_PP) + printk(KERN_DEBUG " PP: control pause packet\n"); + if (em0isr & EMAC_ISR_BP) + printk(KERN_DEBUG " BP: packet error\n"); + if (em0isr & EMAC_ISR_RP) + printk(KERN_DEBUG " RP: runt packet\n"); + if (em0isr & EMAC_ISR_SE) + printk(KERN_DEBUG " SE: short event\n"); + if (em0isr & EMAC_ISR_ALE) + printk(KERN_DEBUG " ALE: odd number of nibbles in packet\n"); + if (em0isr & EMAC_ISR_BFCS) + printk(KERN_DEBUG " BFCS: bad FCS\n"); + if (em0isr & EMAC_ISR_PTLE) + printk(KERN_DEBUG " PTLE: oversized packet\n"); + if (em0isr & EMAC_ISR_ORE) + printk(KERN_DEBUG + " ORE: packet length field > max allowed LLC\n"); + if (em0isr & EMAC_ISR_IRE) + printk(KERN_DEBUG " IRE: In Range error\n"); + if (em0isr & EMAC_ISR_DBDM) + printk(KERN_DEBUG " DBDM: xmit error or SQE\n"); + if (em0isr & EMAC_ISR_DB0) + printk(KERN_DEBUG " DB0: xmit error or SQE on TX channel 0\n"); + if (em0isr & EMAC_ISR_SE0) + printk(KERN_DEBUG + " SE0: Signal Quality Error test failure from TX channel 0\n"); + if (em0isr & EMAC_ISR_TE0) + printk(KERN_DEBUG " TE0: xmit channel 0 aborted\n"); + if (em0isr & EMAC_ISR_DB1) + printk(KERN_DEBUG " DB1: xmit error or SQE on TX channel \n"); + if (em0isr & EMAC_ISR_SE1) + printk(KERN_DEBUG + " SE1: Signal Quality Error test failure from TX channel 1\n"); + if (em0isr & EMAC_ISR_TE1) + printk(KERN_DEBUG " TE1: xmit channel 1 aborted\n"); + if (em0isr & EMAC_ISR_MOS) + printk(KERN_DEBUG " MOS\n"); + if (em0isr & EMAC_ISR_MOF) + printk(KERN_DEBUG " MOF\n"); + + emac_mac_dump(dev); + emac_mal_dump(dev); +} diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c new file mode 100644 index 000000000..02d847cfa --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -0,0 +1,467 @@ +/* + * ibm_ocp_mal.c + * + * Armin Kuster akuster@mvista.com + * Juen, 2002 + * + * Copyright 2002 MontaVista Softare Inc. + * + * 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 +#include +#include +#include + +#include +#include +#include + +#include "ibm_emac_mal.h" + +// Locking: Should we share a lock with the client ? The client could provide +// a lock pointer (optionally) in the commac structure... I don't think this is +// really necessary though + +/* This lock protects the commac list. On today UP implementations, it's + * really only used as IRQ protection in mal_{register,unregister}_commac() + */ +static rwlock_t mal_list_lock = RW_LOCK_UNLOCKED; + +int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + unsigned long flags; + + write_lock_irqsave(&mal_list_lock, flags); + + /* Don't let multiple commacs claim the same channel */ + if ((mal->tx_chan_mask & commac->tx_chan_mask) || + (mal->rx_chan_mask & commac->rx_chan_mask)) { + write_unlock_irqrestore(&mal_list_lock, flags); + return -EBUSY; + } + + mal->tx_chan_mask |= commac->tx_chan_mask; + mal->rx_chan_mask |= commac->rx_chan_mask; + + list_add(&commac->list, &mal->commac); + + write_unlock_irqrestore(&mal_list_lock, flags); + + MOD_INC_USE_COUNT; + + return 0; +} + +int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + unsigned long flags; + + write_lock_irqsave(&mal_list_lock, flags); + + mal->tx_chan_mask &= ~commac->tx_chan_mask; + mal->rx_chan_mask &= ~commac->rx_chan_mask; + + list_del_init(&commac->list); + + write_unlock_irqrestore(&mal_list_lock, flags); + + MOD_DEC_USE_COUNT; + + return 0; +} + +int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) +{ + switch (channel) { + case 0: + set_mal_dcrn(mal, DCRN_MALRCBS0, size); + break; +#ifdef DCRN_MALRCBS1 + case 1: + set_mal_dcrn(mal, DCRN_MALRCBS1, size); + break; +#endif +#ifdef DCRN_MALRCBS2 + case 2: + set_mal_dcrn(mal, DCRN_MALRCBS2, size); + break; +#endif +#ifdef DCRN_MALRCBS3 + case 3: + set_mal_dcrn(mal, DCRN_MALRCBS3, size); + break; +#endif + default: + return -EINVAL; + } + + return 0; +} + +static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + unsigned long mal_error; + + /* + * This SERR applies to one of the devices on the MAL, here we charge + * it against the first EMAC registered for the MAL. + */ + + mal_error = get_mal_dcrn(mal, DCRN_MALESR); + + printk(KERN_ERR "%s: System Error (MALESR=%lx)\n", + "MAL" /* FIXME: get the name right */ , mal_error); + + /* FIXME: decipher error */ + /* DIXME: distribute to commacs, if possible */ + + /* Clear the error status register */ + set_mal_dcrn(mal, DCRN_MALESR, mal_error); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + struct list_head *l; + unsigned long isr; + + isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR); + set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr); + + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + + if (isr & mc->tx_chan_mask) { + mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask); + } + } + read_unlock(&mal_list_lock); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + struct list_head *l; + unsigned long isr; + + isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR); + set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr); + + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + + if (isr & mc->rx_chan_mask) { + mc->ops->rxeob(mc->dev, isr & mc->rx_chan_mask); + } + } + read_unlock(&mal_list_lock); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + struct list_head *l; + unsigned long deir; + + deir = get_mal_dcrn(mal, DCRN_MALTXDEIR); + + /* FIXME: print which MAL correctly */ + printk(KERN_WARNING "%s: Tx descriptor error (MALTXDEIR=%lx)\n", + "MAL", deir); + + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + + if (deir & mc->tx_chan_mask) { + mc->ops->txde(mc->dev, deir & mc->tx_chan_mask); + } + } + read_unlock(&mal_list_lock); + + return IRQ_HANDLED; +} + +/* + * This interrupt should be very rare at best. This occurs when + * the hardware has a problem with the receive descriptors. The manual + * states that it occurs when the hardware cannot the receive descriptor + * empty bit is not set. The recovery mechanism will be to + * traverse through the descriptors, handle any that are marked to be + * handled and reinitialize each along the way. At that point the driver + * will be restarted. + */ +static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + struct list_head *l; + unsigned long deir; + + deir = get_mal_dcrn(mal, DCRN_MALRXDEIR); + + /* + * This really is needed. This case encountered in stress testing. + */ + if (deir == 0) + return IRQ_HANDLED; + + /* FIXME: print which MAL correctly */ + printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n", + "MAL", deir); + + read_lock(&mal_list_lock); + list_for_each(l, &mal->commac) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + + if (deir & mc->rx_chan_mask) { + mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask); + } + } + read_unlock(&mal_list_lock); + + return IRQ_HANDLED; +} + +static int __init mal_probe(struct ocp_device *ocpdev) +{ + struct ibm_ocp_mal *mal = NULL; + struct ocp_func_mal_data *maldata; + int err = 0; + + maldata = (struct ocp_func_mal_data *)ocpdev->def->additions; + if (maldata == NULL) { + printk(KERN_ERR "mal%d: Missing additional datas !\n", + ocpdev->def->index); + return -ENODEV; + } + + mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); + if (mal == NULL) { + printk(KERN_ERR + "mal%d: Out of memory allocating MAL structure !\n", + ocpdev->def->index); + return -ENOMEM; + } + memset(mal, 0, sizeof(*mal)); + + switch (ocpdev->def->index) { + case 0: + mal->dcrbase = DCRN_MAL_BASE; + break; +#ifdef DCRN_MAL1_BASE + case 1: + mal->dcrbase = DCRN_MAL1_BASE; + break; +#endif + default: + BUG(); + } + + /**************************/ + + INIT_LIST_HEAD(&mal->commac); + + set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF); + set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF); + + set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */ + /* FIXME: Add delay */ + + /* Set the MAL configuration register */ + set_mal_dcrn(mal, DCRN_MALCR, + MALCR_PLBB | MALCR_OPBBL | MALCR_LEA | + MALCR_PLBLT_DEFAULT); + + /* It would be nice to allocate buffers separately for each + * channel, but we can't because the channels share the upper + * 13 bits of address lines. Each channels buffer must also + * be 4k aligned, so we allocate 4k for each channel. This is + * inefficient FIXME: do better, if possible */ + mal->tx_virt_addr = dma_alloc_coherent(&ocpdev->dev, + MAL_DT_ALIGN * + maldata->num_tx_chans, + &mal->tx_phys_addr, GFP_KERNEL); + if (mal->tx_virt_addr == NULL) { + printk(KERN_ERR + "mal%d: Out of memory allocating MAL descriptors !\n", + ocpdev->def->index); + err = -ENOMEM; + goto fail; + } + + /* God, oh, god, I hate DCRs */ + set_mal_dcrn(mal, DCRN_MALTXCTP0R, mal->tx_phys_addr); +#ifdef DCRN_MALTXCTP1R + if (maldata->num_tx_chans > 1) + set_mal_dcrn(mal, DCRN_MALTXCTP1R, + mal->tx_phys_addr + MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP1R */ +#ifdef DCRN_MALTXCTP2R + if (maldata->num_tx_chans > 2) + set_mal_dcrn(mal, DCRN_MALTXCTP2R, + mal->tx_phys_addr + 2 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP2R */ +#ifdef DCRN_MALTXCTP3R + if (maldata->num_tx_chans > 3) + set_mal_dcrn(mal, DCRN_MALTXCTP3R, + mal->tx_phys_addr + 3 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP3R */ +#ifdef DCRN_MALTXCTP4R + if (maldata->num_tx_chans > 4) + set_mal_dcrn(mal, DCRN_MALTXCTP4R, + mal->tx_phys_addr + 4 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP4R */ +#ifdef DCRN_MALTXCTP5R + if (maldata->num_tx_chans > 5) + set_mal_dcrn(mal, DCRN_MALTXCTP5R, + mal->tx_phys_addr + 5 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP5R */ +#ifdef DCRN_MALTXCTP6R + if (maldata->num_tx_chans > 6) + set_mal_dcrn(mal, DCRN_MALTXCTP6R, + mal->tx_phys_addr + 6 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP6R */ +#ifdef DCRN_MALTXCTP7R + if (maldata->num_tx_chans > 7) + set_mal_dcrn(mal, DCRN_MALTXCTP7R, + mal->tx_phys_addr + 7 * MAL_DT_ALIGN); +#endif /* DCRN_MALTXCTP7R */ + + mal->rx_virt_addr = dma_alloc_coherent(&ocpdev->dev, + MAL_DT_ALIGN * + maldata->num_rx_chans, + &mal->rx_phys_addr, GFP_KERNEL); + + set_mal_dcrn(mal, DCRN_MALRXCTP0R, mal->rx_phys_addr); +#ifdef DCRN_MALRXCTP1R + if (maldata->num_rx_chans > 1) + set_mal_dcrn(mal, DCRN_MALRXCTP1R, + mal->rx_phys_addr + MAL_DT_ALIGN); +#endif /* DCRN_MALRXCTP1R */ +#ifdef DCRN_MALRXCTP2R + if (maldata->num_rx_chans > 2) + set_mal_dcrn(mal, DCRN_MALRXCTP2R, + mal->rx_phys_addr + 2 * MAL_DT_ALIGN); +#endif /* DCRN_MALRXCTP2R */ +#ifdef DCRN_MALRXCTP3R + if (maldata->num_rx_chans > 3) + set_mal_dcrn(mal, DCRN_MALRXCTP3R, + mal->rx_phys_addr + 3 * MAL_DT_ALIGN); +#endif /* DCRN_MALRXCTP3R */ + + err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal); + if (err) + goto fail; + err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal); + if (err) + goto fail; + err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); + if (err) + goto fail; + err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); + if (err) + goto fail; + err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); + if (err) + goto fail; + + set_mal_dcrn(mal, DCRN_MALIER, + MALIER_DE | MALIER_NE | MALIER_TE | + MALIER_OPBE | MALIER_PLBE); + + /* Advertise me to the rest of the world */ + ocp_set_drvdata(ocpdev, mal); + + printk(KERN_INFO "mal%d: Initialized, %d tx channels, %d rx channels\n", + ocpdev->def->index, maldata->num_tx_chans, + maldata->num_rx_chans); + + return 0; + + fail: + /* FIXME: dispose requested IRQs ! */ + if (err && mal) + kfree(mal); + return err; +} + +static void __exit mal_remove(struct ocp_device *ocpdev) +{ + struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev); + struct ocp_func_mal_data *maldata = ocpdev->def->additions; + + BUG_ON(!maldata); + + ocp_set_drvdata(ocpdev, NULL); + + /* FIXME: shut down the MAL, deal with dependency with emac */ + free_irq(maldata->serr_irq, mal); + free_irq(maldata->txde_irq, mal); + free_irq(maldata->txeob_irq, mal); + free_irq(maldata->rxde_irq, mal); + free_irq(maldata->rxeob_irq, mal); + + if (mal->tx_virt_addr) + dma_free_coherent(&ocpdev->dev, + MAL_DT_ALIGN * maldata->num_tx_chans, + mal->tx_virt_addr, mal->tx_phys_addr); + + if (mal->rx_virt_addr) + dma_free_coherent(&ocpdev->dev, + MAL_DT_ALIGN * maldata->num_rx_chans, + mal->rx_virt_addr, mal->rx_phys_addr); + + kfree(mal); +} + +/* Structure for a device driver */ +static struct ocp_device_id mal_ids[] = { + {.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL}, + {.vendor = OCP_VENDOR_INVALID} +}; + +static struct ocp_driver mal_driver = { + .name = "mal", + .id_table = mal_ids, + + .probe = mal_probe, + .remove = mal_remove, +}; + +static int __init init_mals(void) +{ + int rc; + + rc = ocp_register_driver(&mal_driver); + if (rc < 0) { + ocp_unregister_driver(&mal_driver); + return -ENODEV; + } + + return 0; +} + +static void __exit exit_mals(void) +{ + ocp_unregister_driver(&mal_driver); +} + +module_init(init_mals); +module_exit(exit_mals); diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h new file mode 100644 index 000000000..8e456ce5a --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -0,0 +1,130 @@ +#ifndef _IBM_EMAC_MAL_H +#define _IBM_EMAC_MAL_H + +#include + +#define MAL_DT_ALIGN (4096) /* Alignment for each channel's descriptor table */ + +#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan)) + +/* MAL Buffer Descriptor structure */ +struct mal_descriptor { + unsigned short ctrl; /* MAL / Commac status control bits */ + short data_len; /* Max length is 4K-1 (12 bits) */ + unsigned char *data_ptr; /* pointer to actual data buffer */ +} __attribute__ ((packed)); + +/* the following defines are for the MadMAL status and control registers. */ +/* MADMAL transmit and receive status/control bits */ +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 + +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 + +struct mal_commac_ops { + void (*txeob) (void *dev, u32 chanmask); + void (*txde) (void *dev, u32 chanmask); + void (*rxeob) (void *dev, u32 chanmask); + void (*rxde) (void *dev, u32 chanmask); +}; + +struct mal_commac { + struct mal_commac_ops *ops; + void *dev; + u32 tx_chan_mask, rx_chan_mask; + struct list_head list; +}; + +struct ibm_ocp_mal { + int dcrbase; + + struct list_head commac; + u32 tx_chan_mask, rx_chan_mask; + + dma_addr_t tx_phys_addr; + struct mal_descriptor *tx_virt_addr; + + dma_addr_t rx_phys_addr; + struct mal_descriptor *rx_virt_addr; +}; + +#define GET_MAL_STANZA(base,dcrn) \ + case base: \ + x = mfdcr(dcrn(base)); \ + break; + +#define SET_MAL_STANZA(base,dcrn, val) \ + case base: \ + mtdcr(dcrn(base), (val)); \ + break; + +#define GET_MAL0_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL_BASE,dcrn) +#define SET_MAL0_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL_BASE,dcrn,val) + +#ifdef DCRN_MAL1_BASE +#define GET_MAL1_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL1_BASE,dcrn) +#define SET_MAL1_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL1_BASE,dcrn,val) +#else /* ! DCRN_MAL1_BASE */ +#define GET_MAL1_STANZA(dcrn) +#define SET_MAL1_STANZA(dcrn,val) +#endif + +#define get_mal_dcrn(mal, dcrn) ({ \ + u32 x; \ + switch ((mal)->dcrbase) { \ + GET_MAL0_STANZA(dcrn) \ + GET_MAL1_STANZA(dcrn) \ + default: \ + BUG(); \ + } \ +x; }) + +#define set_mal_dcrn(mal, dcrn, val) do { \ + switch ((mal)->dcrbase) { \ + SET_MAL0_STANZA(dcrn,val) \ + SET_MAL1_STANZA(dcrn,val) \ + default: \ + BUG(); \ + } } while (0) + +static inline void mal_enable_tx_channels(struct ibm_ocp_mal *mal, u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALTXCASR, + get_mal_dcrn(mal, DCRN_MALTXCASR) | chanmask); +} + +static inline void mal_disable_tx_channels(struct ibm_ocp_mal *mal, + u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALTXCARR, chanmask); +} + +static inline void mal_enable_rx_channels(struct ibm_ocp_mal *mal, u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALRXCASR, + get_mal_dcrn(mal, DCRN_MALRXCASR) | chanmask); +} + +static inline void mal_disable_rx_channels(struct ibm_ocp_mal *mal, + u32 chanmask) +{ + set_mal_dcrn(mal, DCRN_MALRXCARR, chanmask); +} + +extern int mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac); +extern int mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac); + +extern int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, + unsigned long size); + +#endif /* _IBM_EMAC_MAL_H */ diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c new file mode 100644 index 000000000..b439087df --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_phy.c @@ -0,0 +1,297 @@ +/* + * ibm_ocp_phy.c + * + * PHY drivers for the ibm ocp ethernet driver. Borrowed + * from sungem_phy.c, though I only kept the generic MII + * driver for now. + * + * This file should be shared with other drivers or eventually + * merged as the "low level" part of miilib + * + * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ibm_emac_phy.h" + +static int reset_one_mii_phy(struct mii_phy *phy, int phy_id) +{ + u16 val; + int limit = 10000; + + val = __phy_read(phy, phy_id, MII_BMCR); + val &= ~BMCR_ISOLATE; + val |= BMCR_RESET; + __phy_write(phy, phy_id, MII_BMCR, val); + + udelay(100); + + while (limit--) { + val = __phy_read(phy, phy_id, MII_BMCR); + if ((val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); + + return (limit <= 0); +} + +static int cis8201_init(struct mii_phy *phy) +{ + u16 epcr; + + epcr = phy_read(phy, MII_CIS8201_EPCR); + epcr &= ~EPCR_MODE_MASK; + + switch (phy->mode) { + case PHY_MODE_TBI: + epcr |= EPCR_TBI_MODE; + break; + case PHY_MODE_RTBI: + epcr |= EPCR_RTBI_MODE; + break; + case PHY_MODE_GMII: + epcr |= EPCR_GMII_MODE; + break; + case PHY_MODE_RGMII: + default: + epcr |= EPCR_RGMII_MODE; + } + + phy_write(phy, MII_CIS8201_EPCR, epcr); + + return 0; +} + +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + u16 ctl, adv; + + phy->autoneg = 1; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(phy, MII_ADVERTISE, adv); + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + u16 ctl; + + phy->autoneg = 0; + phy->speed = speed; + phy->duplex = fd; + phy->pause = 0; + + ctl = phy_read(phy, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); + + /* First reset the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch (speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + u16 status; + + (void)phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +#define MII_CIS8201_ACSR 0x1c +#define ACSR_DUPLEX_STATUS 0x0020 +#define ACSR_SPEED_1000BASET 0x0010 +#define ACSR_SPEED_100BASET 0x0008 + +static int cis8201_read_link(struct mii_phy *phy) +{ + u16 acsr; + + if (phy->autoneg) { + acsr = phy_read(phy, MII_CIS8201_ACSR); + + if (acsr & ACSR_DUPLEX_STATUS) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (acsr & ACSR_SPEED_1000BASET) { + phy->speed = SPEED_1000; + } else if (acsr & ACSR_SPEED_100BASET) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + phy->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + u16 lpa; + + if (phy->autoneg) { + lpa = phy_read(phy, MII_LPA); + + if (lpa & (LPA_10FULL | LPA_100FULL)) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (lpa & (LPA_100FULL | LPA_100HALF)) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + phy->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) + +/* CIS8201 phy ops */ +static struct mii_phy_ops cis8201_phy_ops = { + init:cis8201_init, + setup_aneg:genmii_setup_aneg, + setup_forced:genmii_setup_forced, + poll_link:genmii_poll_link, + read_link:cis8201_read_link +}; + +/* Generic implementation for most 10/100 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + setup_aneg:genmii_setup_aneg, + setup_forced:genmii_setup_forced, + poll_link:genmii_poll_link, + read_link:genmii_read_link +}; + +static struct mii_phy_def cis8201_phy_def = { + phy_id:0x000fc410, + phy_id_mask:0x000ffff0, + name:"CIS8201 Gigabit Ethernet", + features:MII_GBIT_FEATURES, + magic_aneg:0, + ops:&cis8201_phy_ops +}; + +static struct mii_phy_def genmii_phy_def = { + phy_id:0x00000000, + phy_id_mask:0x00000000, + name:"Generic MII", + features:MII_BASIC_FEATURES, + magic_aneg:0, + ops:&generic_phy_ops +}; + +static struct mii_phy_def *mii_phy_table[] = { + &cis8201_phy_def, + &genmii_phy_def, + NULL +}; + +int mii_phy_probe(struct mii_phy *phy, int mii_id) +{ + int rc; + u32 id; + struct mii_phy_def *def; + int i; + + phy->autoneg = 0; + phy->advertising = 0; + phy->mii_id = mii_id; + phy->speed = 0; + phy->duplex = 0; + phy->pause = 0; + + /* Take PHY out of isloate mode and reset it. */ + rc = reset_one_mii_phy(phy, mii_id); + if (rc) + return -ENODEV; + + /* Read ID and find matching entry */ + id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) + & 0xfffffff0; + for (i = 0; (def = mii_phy_table[i]) != NULL; i++) + if ((id & def->phy_id_mask) == def->phy_id) + break; + /* Should never be NULL (we have a generic entry), but... */ + if (def == NULL) + return -ENODEV; + + phy->def = def; + + /* Setup default advertising */ + phy->advertising = def->features; + + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h new file mode 100644 index 000000000..49f188f4e --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -0,0 +1,65 @@ +/* + * Defines for the IBM RGMII bridge + * + * Based on ocp_zmii.h/ibm_emac_zmii.h + * Armin Kuster akuster@mvista.com + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * 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. + */ + +#ifndef _IBM_EMAC_RGMII_H_ +#define _IBM_EMAC_RGMII_H_ + +#include + +/* RGMII bridge */ +typedef struct rgmii_regs { + u32 fer; /* Function enable register */ + u32 ssr; /* Speed select register */ +} rgmii_t; + +#define RGMII_INPUTS 4 + +/* RGMII device */ +struct ibm_ocp_rgmii { + struct rgmii_regs *base; + int mode[RGMII_INPUTS]; + int users; /* number of EMACs using this RGMII bridge */ +}; + +/* Fuctional Enable Reg */ +#define RGMII_FER_MASK(x) (0x00000007 << (4*x)) +#define RGMII_RTBI 0x00000004 +#define RGMII_RGMII 0x00000005 +#define RGMII_TBI 0x00000006 +#define RGMII_GMII 0x00000007 + +/* Speed Selection reg */ + +#define RGMII_SP2_100 0x00000002 +#define RGMII_SP2_1000 0x00000004 +#define RGMII_SP3_100 0x00000200 +#define RGMII_SP3_1000 0x00000400 + +#define RGMII_MII2_SPDMASK 0x00000007 +#define RGMII_MII3_SPDMASK 0x00000700 + +#define RGMII_MII2_100MB RGMII_SP2_100 & ~RGMII_SP2_1000 +#define RGMII_MII2_1000MB RGMII_SP2_1000 & ~RGMII_SP2_100 +#define RGMII_MII2_10MB ~(RGMII_SP2_100 | RGMII_SP2_1000) +#define RGMII_MII3_100MB RGMII_SP3_100 & ~RGMII_SP3_1000 +#define RGMII_MII3_1000MB RGMII_SP3_1000 & ~RGMII_SP3_100 +#define RGMII_MII3_10MB ~(RGMII_SP3_100 | RGMII_SP3_1000) + +#define RTBI 0 +#define RGMII 1 +#define TBI 2 +#define GMII 3 + +#endif /* _IBM_EMAC_RGMII_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_tah.h b/drivers/net/ibm_emac/ibm_emac_tah.h new file mode 100644 index 000000000..ecfc69805 --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_tah.h @@ -0,0 +1,48 @@ +/* + * Defines for the IBM TAH + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * 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. + */ + +#ifndef _IBM_EMAC_TAH_H +#define _IBM_EMAC_TAH_H + +/* TAH */ +typedef struct tah_regs { + u32 tah_revid; + u32 pad[3]; + u32 tah_mr; + u32 tah_ssr0; + u32 tah_ssr1; + u32 tah_ssr2; + u32 tah_ssr3; + u32 tah_ssr4; + u32 tah_ssr5; + u32 tah_tsr; +} tah_t; + +/* TAH engine */ +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 + +#endif /* _IBM_EMAC_TAH_H */ diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h new file mode 100644 index 000000000..6f6cd2a39 --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_zmii.h @@ -0,0 +1,93 @@ +/* + * ocp_zmii.h + * + * Defines for the IBM ZMII bridge + * + * Armin Kuster akuster@mvista.com + * Dec, 2001 + * + * Copyright 2001 MontaVista Softare Inc. + * + * 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. + */ + +#ifndef _IBM_EMAC_ZMII_H_ +#define _IBM_EMAC_ZMII_H_ + +#include + +/* ZMII bridge registers */ +struct zmii_regs { + u32 fer; /* Function enable reg */ + u32 ssr; /* Speed select reg */ + u32 smiirs; /* SMII status reg */ +}; + +#define ZMII_INPUTS 4 + +/* ZMII device */ +struct ibm_ocp_zmii { + struct zmii_regs *base; + int mode[ZMII_INPUTS]; + int users; /* number of EMACs using this ZMII bridge */ +}; + +/* Fuctional Enable Reg */ + +#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x)) + +#define ZMII_MDI0 0x80000000 +#define ZMII_SMII0 0x40000000 +#define ZMII_RMII0 0x20000000 +#define ZMII_MII0 0x10000000 +#define ZMII_MDI1 0x08000000 +#define ZMII_SMII1 0x04000000 +#define ZMII_RMII1 0x02000000 +#define ZMII_MII1 0x01000000 +#define ZMII_MDI2 0x00800000 +#define ZMII_SMII2 0x00400000 +#define ZMII_RMII2 0x00200000 +#define ZMII_MII2 0x00100000 +#define ZMII_MDI3 0x00080000 +#define ZMII_SMII3 0x00040000 +#define ZMII_RMII3 0x00020000 +#define ZMII_MII3 0x00010000 + +/* Speed Selection reg */ + +#define ZMII_SCI0 0x40000000 +#define ZMII_FSS0 0x20000000 +#define ZMII_SP0 0x10000000 +#define ZMII_SCI1 0x04000000 +#define ZMII_FSS1 0x02000000 +#define ZMII_SP1 0x01000000 +#define ZMII_SCI2 0x00400000 +#define ZMII_FSS2 0x00200000 +#define ZMII_SP2 0x00100000 +#define ZMII_SCI3 0x00040000 +#define ZMII_FSS3 0x00020000 +#define ZMII_SP3 0x00010000 + +#define ZMII_MII0_100MB ZMII_SP0 +#define ZMII_MII0_10MB ~ZMII_SP0 +#define ZMII_MII1_100MB ZMII_SP1 +#define ZMII_MII1_10MB ~ZMII_SP1 +#define ZMII_MII2_100MB ZMII_SP2 +#define ZMII_MII2_10MB ~ZMII_SP2 +#define ZMII_MII3_100MB ZMII_SP3 +#define ZMII_MII3_10MB ~ZMII_SP3 + +/* SMII Status reg */ + +#define ZMII_STS0 0xFF000000 /* EMAC0 smii status mask */ +#define ZMII_STS1 0x00FF0000 /* EMAC1 smii status mask */ + +#define SMII 0 +#define RMII 1 +#define MII 2 +#define MDI 3 + +#endif /* _IBM_EMAC_ZMII_H_ */ diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 654fd6907..a93cda669 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1529,12 +1529,11 @@ static struct ethtool_ops ioc3_ethtool_ops = { static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; struct ioc3_private *ip = netdev_priv(dev); int rc; spin_lock_irq(&ip->ioc3_lock); - rc = generic_mii_ioctl(&ip->mii, data, cmd, NULL); + rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL); spin_unlock_irq(&ip->ioc3_lock); return rc; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 9bae8d9ab..8c45911fe 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1961,12 +1961,12 @@ static void set_rx_mode(struct net_device *dev) spin_unlock_irq(&np->lock); } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct netdev_private *np = dev->priv; u32 cmd; - if (get_user(cmd, (u32 *)useraddr)) + if (get_user(cmd, (u32 __user *)useraddr)) return -EFAULT; switch (cmd) { @@ -2417,11 +2417,11 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); switch(cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(dev, rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = 1; diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c new file mode 100644 index 000000000..86f34b5ec --- /dev/null +++ b/drivers/net/ne-h8300.c @@ -0,0 +1,666 @@ +/* ne-h8300.c: A NE2000 clone on H8/300 driver for linux. */ +/* + original ne.c + Written 1992-94 by Donald Becker. + + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 + + H8/300 modified + Yoshinori Sato +*/ + +static const char version1[] = +"ne-h8300.c:v1.00 2004/04/11 ysato\n"; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "8390.h" + +/* Some defines that people can play with if so inclined. */ + +/* Do we perform extra sanity checks on stuff ? */ +/* #define NE_SANITY_CHECK */ + +/* Do we implement the read before write bugfix ? */ +/* #define NE_RW_BUGFIX */ + +/* Do we have a non std. amount of memory? (in units of 256 byte pages) */ +/* #define PACKETBUF_MEMSIZE 0x40 */ + +/* A zero-terminated list of I/O addresses to be probed at boot. */ + +/* ---- No user-serviceable parts below ---- */ + +#define NE_BASE (dev->base_addr) +#define NE_CMD 0x00 +#define NE_DATAPORT (ei_status.word16?0x20:0x10) /* NatSemi-defined port window offset. */ +#define NE_RESET (ei_status.word16?0x3f:0x1f) /* Issue a read to reset, a write to clear. */ +#define NE_IO_EXTENT (ei_status.word16?0x40:0x20) + +#define NESM_START_PG 0x40 /* First page of TX buffer */ +#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ + +static int ne_probe1(struct net_device *dev, int ioaddr); + +static int ne_open(struct net_device *dev); +static int ne_close(struct net_device *dev); + +static void ne_reset_8390(struct net_device *dev); +static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void ne_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void ne_block_output(struct net_device *dev, const int count, + const unsigned char *buf, const int start_page); + + +static u32 reg_offset[16]; + +static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr) +{ + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + int i; + unsigned char bus_width; + + bus_width = *(volatile unsigned char *)ABWCR; + bus_width &= 1 << ((base_addr >> 21) & 7); + + for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++) + if (bus_width == 0) + reg_offset[i] = i * 2 + 1; + else + reg_offset[i] = i; + + ei_local->reg_offset = reg_offset; + return 0; +} + +static int __initdata h8300_ne_count = 0; +#ifdef CONFIG_H8300H_H8MAX +static unsigned long __initdata h8300_ne_base[] = { 0x800600 }; +static int h8300_ne_irq[] = {EXT_IRQ4}; +#endif +#ifdef CONFIG_H8300H_AKI3068NET +static unsigned long __initdata h8300_ne_base[] = { 0x200000 }; +static int h8300_ne_irq[] = {EXT_IRQ5}; +#endif + +static inline int init_dev(struct net_device *dev) +{ + if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) { + dev->base_addr = h8300_ne_base[h8300_ne_count]; + dev->irq = h8300_ne_irq[h8300_ne_count]; + h8300_ne_count++; + return 0; + } else + return -ENODEV; +} + +/* Probe for various non-shared-memory ethercards. + + NEx000-clone boards have a Station Address PROM (SAPROM) in the packet + buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of + the SAPROM, while other supposed NE2000 clones must be detected by their + SA prefix. + + Reading the SAPROM from a word-wide card with the 8390 set in byte-wide + mode results in doubled values, which can be detected and compensated for. + + The probe is also responsible for initializing the card and filling + in the 'dev' and 'ei_status' structures. + + We use the minimum memory size for some ethercard product lines, iff we can't + distinguish models. You can increase the packet buffer size by setting + PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: + E1010 starts at 0x100 and ends at 0x2000. + E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") + E2010 starts at 0x100 and ends at 0x4000. + E2010-x starts at 0x100 and ends at 0xffff. */ + +static int __init do_ne_probe(struct net_device *dev) +{ + unsigned int base_addr = dev->base_addr; + + SET_MODULE_OWNER(dev); + + /* First check any supplied i/o locations. User knows best. */ + if (base_addr > 0x1ff) /* Check a single specified location. */ + return ne_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + + return -ENODEV; +} + +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (init_dev(dev)) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = init_reg_offset(dev, dev->base_addr); + if (err) + goto out; + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + +static int __init ne_probe1(struct net_device *dev, int ioaddr) +{ + int i; + unsigned char SA_prom[16]; + int wordlength = 2; + const char *name = NULL; + int start_page, stop_page; + int reg0, ret; + static unsigned version_printed; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + unsigned char bus_width; + + if (!request_region(ioaddr, NE_IO_EXTENT, dev->name)) + return -EBUSY; + + reg0 = inb_p(ioaddr); + if (reg0 == 0xFF) { + ret = -ENODEV; + goto err_out; + } + + /* Do a preliminary verification that we have a 8390. */ + { + int regd; + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + regd = inb_p(ioaddr + EI_SHIFT(0x0d)); + outb_p(0xff, ioaddr + EI_SHIFT(0x0d)); + outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); + inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ + if (inb_p(ioaddr + EN0_COUNTER0) != 0) { + outb_p(reg0, ioaddr + EI_SHIFT(0)); + outb_p(regd, ioaddr + EI_SHIFT(0x0d)); /* Restore the old values. */ + ret = -ENODEV; + goto err_out; + } + } + + if (ei_debug && version_printed++ == 0) + printk(KERN_INFO "%s", version1); + + printk(KERN_INFO "NE*000 ethercard probe at %08x:", ioaddr); + + /* Read the 16 bytes of station address PROM. + We must first initialize registers, similar to NS8390_init(eifdev, 0). + We can't reliably read the SAPROM address without this. + (I learned the hard way!). */ + { + struct {unsigned char value, offset; } program_seq[] = + { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + + } + bus_width = *(volatile unsigned char *)ABWCR; + bus_width &= 1 << ((ioaddr >> 21) & 7); + ei_status.word16 = (bus_width == 0); /* temporary setting */ + for(i = 0; i < 16 /*sizeof(SA_prom)*/; i++) { + SA_prom[i] = inb_p(ioaddr + NE_DATAPORT); + inb_p(ioaddr + NE_DATAPORT); /* dummy read */ + } + + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + + if (bus_width) + wordlength = 1; + else + outb_p(0x49, ioaddr + EN0_DCFG); + + /* Set up the rest of the parameters. */ + name = (wordlength == 2) ? "NE2000" : "NE1000"; + + if (! dev->irq) { + printk(" failed to detect IRQ line.\n"); + ret = -EAGAIN; + goto err_out; + } + + /* Snarf the interrupt now. There's no point in waiting since we cannot + share and the board will usually be enabled. */ + ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); + if (ret) { + printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); + goto err_out; + } + + dev->base_addr = ioaddr; + + for(i = 0; i < ETHER_ADDR_LEN; i++) { + printk(" %2.2x", SA_prom[i]); + dev->dev_addr[i] = SA_prom[i]; + } + + printk("\n%s: %s found at %#x, using IRQ %d.\n", + dev->name, name, ioaddr, dev->irq); + + ei_status.name = name; + ei_status.tx_start_page = start_page; + ei_status.stop_page = stop_page; + ei_status.word16 = (wordlength == 2); + + ei_status.rx_start_page = start_page + TX_PAGES; +#ifdef PACKETBUF_MEMSIZE + /* Allow the packet buffer size to be overridden by know-it-alls. */ + ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; +#endif + + ei_status.reset_8390 = &ne_reset_8390; + ei_status.block_input = &ne_block_input; + ei_status.block_output = &ne_block_output; + ei_status.get_8390_hdr = &ne_get_8390_hdr; + ei_status.priv = 0; + dev->open = &ne_open; + dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); + return 0; + +err_out: + release_region(ioaddr, NE_IO_EXTENT); + return ret; +} + +static int ne_open(struct net_device *dev) +{ + ei_open(dev); + return 0; +} + +static int ne_close(struct net_device *dev) +{ + if (ei_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); + ei_close(dev); + return 0; +} + +/* Hard reset the card. This used to pause for the same period that a + 8390 reset command required, but that shouldn't be necessary. */ + +static void ne_reset_8390(struct net_device *dev) +{ + unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + + if (ei_debug > 1) + printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); + + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + + ei_status.txing = 0; + ei_status.dmaing = 0; + + /* This check _should_not_ be necessary, omit eventually. */ + while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); + break; + } + outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ +} + +/* Grab the 8390 specific header. Similar to the block_input routine, but + we don't need to be concerned with ring wrap as the header will be at + the start of a page, so we optimize accordingly. */ + +static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, NE_BASE + NE_CMD); + outb_p(sizeof(struct e8390_pkt_hdr), NE_BASE + EN0_RCNTLO); + outb_p(0, NE_BASE + EN0_RCNTHI); + outb_p(0, NE_BASE + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, NE_BASE + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); + + if (ei_status.word16) { + int len; + unsigned short *p = (unsigned short *)hdr; + for (len = sizeof(struct e8390_pkt_hdr)>>1; len > 0; len--) + *p++ = inw(NE_BASE + NE_DATAPORT); + } else + insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); + + outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + + le16_to_cpus(&hdr->count); +} + +/* Block input and output, similar to the Crynwr packet driver. If you + are porting to a new ethercard, look at the packet driver source for hints. + The NEx000 doesn't share the on-board packet memory -- you have to put + the packet out through the "remote DMA" dataport using outb. */ + +static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); +#ifdef NE_SANITY_CHECK + int xfer_count = count; +#endif + char *buf = skb->data; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, NE_BASE + NE_CMD); + outb_p(count & 0xff, NE_BASE + EN0_RCNTLO); + outb_p(count >> 8, NE_BASE + EN0_RCNTHI); + outb_p(ring_offset & 0xff, NE_BASE + EN0_RSARLO); + outb_p(ring_offset >> 8, NE_BASE + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); + if (ei_status.word16) + { + int len; + unsigned short *p = (unsigned short *)buf; + for (len = count>>1; len > 0; len--) + *p++ = inw(NE_BASE + NE_DATAPORT); + if (count & 0x01) + { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); +#ifdef NE_SANITY_CHECK + xfer_count++; +#endif + } + } else { + insb(NE_BASE + NE_DATAPORT, buf, count); + } + +#ifdef NE_SANITY_CHECK + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. If you see + this message you either 1) have a slightly incompatible clone + or 2) have noise/speed problems with your bus. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken for Rx on some cards! */ + int high = inb_p(NE_BASE + EN0_RSARHI); + int low = inb_p(NE_BASE + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + xfer_count) & 0xff) == low) + break; + } while (--tries > 0); + if (tries <= 0) + printk(KERN_WARNING "%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } +#endif + outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; +} + +static void ne_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); + unsigned long dma_start; +#ifdef NE_SANITY_CHECK + int retries = 0; +#endif + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + + if (ei_status.word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, NE_BASE + NE_CMD); + +#ifdef NE_SANITY_CHECK +retry: +#endif + +#ifdef NE8390_RW_BUGFIX + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. + Actually this doesn't always work either, but if you have + problems with your NEx000 this is better than nothing! */ + + outb_p(0x42, NE_BASE + EN0_RCNTLO); + outb_p(0x00, NE_BASE + EN0_RCNTHI); + outb_p(0x42, NE_BASE + EN0_RSARLO); + outb_p(0x00, NE_BASE + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); + /* Make certain that the dummy read has occurred. */ + udelay(6); +#endif + + outb_p(ENISR_RDC, NE_BASE + EN0_ISR); + + /* Now the normal output. */ + outb_p(count & 0xff, NE_BASE + EN0_RCNTLO); + outb_p(count >> 8, NE_BASE + EN0_RCNTHI); + outb_p(0x00, NE_BASE + EN0_RSARLO); + outb_p(start_page, NE_BASE + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, NE_BASE + NE_CMD); + if (ei_status.word16) { + int len; + unsigned short *p = (unsigned short *)buf; + for (len = count>>1; len > 0; len--) + outw(*p++, NE_BASE + NE_DATAPORT); + } else { + outsb(NE_BASE + NE_DATAPORT, buf, count); + } + + dma_start = jiffies; + +#ifdef NE_SANITY_CHECK + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + int high = inb_p(NE_BASE + EN0_RSARHI); + int low = inb_p(NE_BASE + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + + if (tries <= 0) + { + printk(KERN_WARNING "%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } + } +#endif + + while ((inb_p(NE_BASE + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); + ne_reset_8390(dev); + NS8390_init(dev,1); + break; + } + + outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + return; +} + + +#ifdef MODULE +#define MAX_NE_CARDS 1 /* Max number of NE cards per module */ +static struct net_device *dev_ne[MAX_NE_CARDS]; +static int io[MAX_NE_CARDS]; +static int irq[MAX_NE_CARDS]; +static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ + +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM_DESC(io, "I/O base address(es)"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_DESCRIPTION("H8/300 NE2000 Ethernet driver"); +MODULE_LICENSE("GPL"); + +/* This is set up so that no ISA autoprobe takes place. We can't guarantee +that the ne2k probe is the last 8390 based probe to take place (as it +is at boot) and so the probe will get confused by any other 8390 cards. +ISA device autoprobes on a running machine are not recommended anyway. */ + +int init_module(void) +{ + int this_dev, found = 0; + int err; + + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; + if (io[this_dev]) { + dev->irq = irq[this_dev]; + dev->mem_end = bad[this_dev]; + dev->base_addr = io[this_dev]; + } else { + dev->base_addr = h8300_ne_base[this_dev]; + dev->irq = h8300_ne_irq[this_dev]; + } + err = init_reg_offset(dev, dev->base_addr); + if (!err) { + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); + } + } + free_netdev(dev); + if (found) + break; + if (io[this_dev] != 0) + printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", dev->base_addr); + else + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); + return -ENXIO; + } + if (found) + return 0; + return -ENODEV; +} + +void cleanup_module(void) +{ + int this_dev; + + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + struct net_device *dev = dev_ne[this_dev]; + if (dev) { + unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); + } + } +} +#endif /* MODULE */ diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 41fc5f9df..0ff2d4223 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1190,7 +1190,7 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) return &dev->stats; } -static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr) +static int ns83820_ethtool_ioctl (struct ns83820 *dev, void __user *useraddr) { u32 ethcmd; @@ -1236,7 +1236,7 @@ static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) switch(cmd) { case SIOCETHTOOL: - return ns83820_ethtool_ioctl(dev, (void *) rq->ifr_data); + return ns83820_ethtool_ioctl(dev, rq->ifr_data); default: return -EOPNOTSUPP; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 28d8b5342..238538660 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1778,7 +1778,7 @@ static int netdrv_close (struct net_device *dev) static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct netdrv_private *tp = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); unsigned long flags; int rc = 0; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 47a102fd6..59d80ebbe 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1196,7 +1196,7 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; int phy = lp->phys & 0x1f; DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d073093dd..b53f5fcf5 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1281,7 +1281,7 @@ static struct ethtool_ops netdev_ethtool_ops = { static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { pcnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; switch (cmd) { case SIOCGMIIPHY: diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 13ed04f1b..7c1bd346e 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -2119,12 +2119,12 @@ static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) return 0; } -static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr) +static int smc_ethtool_ioctl (struct net_device *dev, void __user *useraddr) { u32 ethcmd; struct smc_private *smc = netdev_priv(dev); - if (get_user(ethcmd, (u32 *)useraddr)) + if (get_user(ethcmd, (u32 __user *)useraddr)) return -EFAULT; switch (ethcmd) { @@ -2221,7 +2221,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) u_short saved_bank; ioaddr_t ioaddr = dev->base_addr; - mii = (struct mii_ioctl_data *) &rq->ifr_data; + mii = if_mii(rq); if (!netif_running(dev)) return -EINVAL; @@ -2229,7 +2229,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case SIOCETHTOOL: saved_bank = inw(ioaddr + BANK_SELECT); SMC_SELECT_BANK(3); - rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data); + rc = smc_ethtool_ioctl(dev, rq->ifr_data); SMC_SELECT_BANK(saved_bank); break; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 5671f1234..d4cc26902 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1681,7 +1681,7 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { local_info_t *local = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index a6d09dd83..d77314518 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1715,7 +1715,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return error; case SIOCRRID: - return put_user(0x52523032, (int *)(&rq->ifr_data[0])); + return put_user(0x52523032, (int __user *)rq->ifr_data); default: return error; } diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 0b15d6513..7914167ac 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2721,7 +2721,7 @@ static void sbmac_set_rx_mode(struct net_device *dev) static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct sbmac_softc *sc = netdev_priv(dev); - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; unsigned long flags; int retval; diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 9352fc63c..2351e186a 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -579,7 +579,7 @@ static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data; + struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru; struct shaper *sh=dev->priv; if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED) diff --git a/drivers/net/slip.c b/drivers/net/slip.c index e783ac0fa..a8967112f 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1138,6 +1138,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm { struct slip *sl = (struct slip *) tty->disc_data; unsigned int tmp; + int __user *p = (int __user *)arg; /* First make sure we're connected. */ if (!sl || sl->magic != SLIP_MAGIC) { @@ -1147,17 +1148,17 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm switch(cmd) { case SIOCGIFNAME: tmp = strlen(sl->dev->name) + 1; - if (copy_to_user((void *)arg, sl->dev->name, tmp)) + if (copy_to_user((void __user *)arg, sl->dev->name, tmp)) return -EFAULT; return 0; case SIOCGIFENCAP: - if (put_user(sl->mode, (int *)arg)) + if (put_user(sl->mode, p)) return -EFAULT; return 0; case SIOCSIFENCAP: - if (get_user(tmp,(int *)arg)) + if (get_user(tmp, p)) return -EFAULT; #ifndef SL_INCLUDE_CSLIP if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) { @@ -1185,7 +1186,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm #ifdef CONFIG_SLIP_SMART /* VSV changes start here */ case SIOCSKEEPALIVE: - if (get_user(tmp,(int *)arg)) + if (get_user(tmp, p)) return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; @@ -1205,12 +1206,12 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm return 0; case SIOCGKEEPALIVE: - if (put_user(sl->keepalive, (int *)arg)) + if (put_user(sl->keepalive, p)) return -EFAULT; return 0; case SIOCSOUTFILL: - if (get_user(tmp,(int *)arg)) + if (get_user(tmp, p)) return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; @@ -1229,7 +1230,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm return 0; case SIOCGOUTFILL: - if (put_user(sl->outfill, (int *)arg)) + if (put_user(sl->outfill, p)) return -EFAULT; return 0; /* VSV changes end */ @@ -1254,6 +1255,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) { struct slip *sl = (struct slip*)(dev->priv); + unsigned long *p = (unsigned long *)&rq->ifr_ifru; if (sl == NULL) /* Allocation failed ?? */ return -ENODEV; @@ -1268,11 +1270,11 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) switch(cmd){ case SIOCSKEEPALIVE: /* max for unchar */ - if (((unsigned int)((unsigned long)rq->ifr_data)) > 255) { + if ((unsigned)*p > 255) { spin_unlock_bh(&sl->lock); return -EINVAL; } - sl->keepalive = (unchar) ((unsigned long)rq->ifr_data); + sl->keepalive = (unchar) *p; if (sl->keepalive != 0) { sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); @@ -1283,15 +1285,15 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) break; case SIOCGKEEPALIVE: - rq->ifr_data=(caddr_t)((unsigned long)sl->keepalive); + *p = sl->keepalive; break; case SIOCSOUTFILL: - if (((unsigned)((unsigned long)rq->ifr_data)) > 255) { /* max for unchar */ + if ((unsigned)*p > 255) { /* max for unchar */ spin_unlock_bh(&sl->lock); return -EINVAL; } - if ((sl->outfill = (unchar)((unsigned long) rq->ifr_data)) != 0){ + if ((sl->outfill = (unchar)*p) != 0){ mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); set_bit(SLF_OUTWAIT, &sl->flags); } else { @@ -1300,7 +1302,7 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) break; case SIOCGOUTFILL: - rq->ifr_data=(caddr_t)((unsigned long)sl->outfill); + *p = sl->outfill; break; case SIOCSLEASE: @@ -1312,12 +1314,12 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) return -EPERM; } sl->leased = 0; - if ((unsigned long)rq->ifr_data) + if (*p) sl->leased = 1; break; case SIOCGLEASE: - rq->ifr_data=(caddr_t)((unsigned long)sl->leased); + *p = sl->leased; }; spin_unlock_bh(&sl->lock); return 0; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 9b47edbd9..0eb660aa7 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1997,7 +1997,7 @@ static void set_rx_mode(struct net_device *dev) } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct ethtool_cmd ecmd; struct netdev_private *np = dev->priv; @@ -2079,16 +2079,16 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; if (!netif_running(dev)) return -EINVAL; if (cmd == SIOCETHTOOL) - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + rc = netdev_ethtool_ioctl(dev, rq->ifr_data); else { + struct mii_ioctl_data *data = if_mii(rq); spin_lock_irq(&np->lock); rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); spin_unlock_irq(&np->lock); diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 838c9c50a..e5069fca1 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1576,7 +1576,7 @@ static int __set_mac_addr(struct net_device *dev) } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct netdev_private *np = dev->priv; u32 ethcmd; @@ -1659,7 +1659,6 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; int i; long ioaddr = dev->base_addr; @@ -1668,11 +1667,11 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EINVAL; if (cmd == SIOCETHTOOL) - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + rc = netdev_ethtool_ioctl(dev, rq->ifr_data); else { spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); + rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irq(&np->lock); } switch (cmd) { diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 36ddb6d84..cb890cd3e 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2510,7 +2510,7 @@ static struct ethtool_ops gem_ethtool_ops = { static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct gem *gp = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct mii_ioctl_data *data = if_mii(ifr); int rc = -EOPNOTSUPP; /* Hold the PM semaphore while doing ioctl's or we may collide diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 3fb06e5cb..d59d46ecd 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -5535,7 +5535,7 @@ static int de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct de4x5_private *lp = netdev_priv(dev); - struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; + struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_ifru; u_long iobase = dev->base_addr; int i, j, status = 0; s32 omr; diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h index 7f02aacd3..ad37a4074 100644 --- a/drivers/net/tulip/de4x5.h +++ b/drivers/net/tulip/de4x5.h @@ -1005,7 +1005,7 @@ struct de4x5_ioctl { unsigned short cmd; /* Command to run */ unsigned short len; /* Length of the data buffer */ - unsigned char *data; /* Pointer to the data buffer */ + unsigned char __user *data; /* Pointer to the data buffer */ }; /* diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index cb0e30486..f86170e9b 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -133,6 +133,10 @@ int tulip_poll(struct net_device *dev, int *budget) tp->rx_ring[entry].status); do { + if (inl(dev->base_addr + CSR5) == 0xffffffff) { + printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n"); + break; + } /* Acknowledge current RX interrupt sources. */ outl((RxIntr | RxNoBuf), dev->base_addr + CSR5); diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index 5f6cea1b2..a01cc1b09 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -1369,7 +1369,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev) } -static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int xircom_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct ethtool_cmd ecmd; struct xircom_private *tp = dev->priv; @@ -1471,13 +1471,13 @@ static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr) static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct xircom_private *tp = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *)&rq->ifr_ifru; int phy = tp->phys[0] & 0x1f; unsigned long flags; switch(cmd) { case SIOCETHTOOL: - return xircom_ethtool_ioctl(dev, (void *) rq->ifr_data); + return xircom_ethtool_ioctl(dev, rq->ifr_data); /* Legacy mii-diag interface */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e6df23fea..d0fe0f656 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -129,8 +129,8 @@ static void tun_net_init(struct net_device *dev) dev->addr_len = 0; dev->mtu = 1500; - /* Type PPP seems most suitable */ - dev->type = ARPHRD_PPP; + /* Zero header length */ + dev->type = ARPHRD_NONE; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->tx_queue_len = 10; break; @@ -241,10 +241,10 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, } /* Write */ -static ssize_t tun_chr_write(struct file * file, const char * buf, +static ssize_t tun_chr_write(struct file * file, const char __user * buf, size_t count, loff_t *pos) { - struct iovec iv = { (void *) buf, count }; + struct iovec iv = { (void __user *) buf, count }; return tun_chr_writev(file, &iv, 1, pos); } @@ -333,7 +333,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, } /* Read */ -static ssize_t tun_chr_read(struct file * file, char * buf, +static ssize_t tun_chr_read(struct file * file, char __user * buf, size_t count, loff_t *pos) { struct iovec iv = { buf, count }; @@ -462,7 +462,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, struct ifreq ifr; int err; - if (copy_from_user(&ifr, (void *)arg, sizeof(ifr))) + if (copy_from_user(&ifr, (void __user *)arg, sizeof(ifr))) return -EFAULT; ifr.ifr_name[IFNAMSIZ-1] = '\0'; @@ -473,7 +473,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, if (err) return err; - if (copy_to_user((void *)arg, &ifr, sizeof(ifr))) + if (copy_to_user((void __user *)arg, &ifr, sizeof(ifr))) return -EFAULT; return 0; } diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 39949dbb1..45ab1999d 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1162,7 +1162,7 @@ typhoon_ethtool_sset(struct typhoon *tp, struct ethtool_cmd *cmd) } static inline int -typhoon_ethtool_ioctl(struct net_device *dev, void *useraddr) +typhoon_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct typhoon *tp = (struct typhoon *) dev->priv; u32 ethcmd; @@ -1237,7 +1237,7 @@ typhoon_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { switch (cmd) { case SIOCETHTOOL: - return typhoon_ethtool_ioctl(dev, (void *) ifr->ifr_data); + return typhoon_ethtool_ioctl(dev, ifr->ifr_data); default: break; } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 82798fd0e..bad0d4185 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -229,7 +229,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) return(ret); } -static int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get) +static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get) { struct dlci_conf config; struct dlci_local *dlp; @@ -286,7 +286,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!*(short *)(dev->dev_addr)) return(-EINVAL); - return(dlci_config(dev, (struct dlci_conf *) ifr->ifr_data, cmd == DLCI_GET_CONF)); + return(dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF)); break; default: @@ -454,7 +454,7 @@ static int dlci_del(struct dlci_add *dlci) return(err); } -static int dlci_ioctl(unsigned int cmd, void *arg) +static int dlci_ioctl(unsigned int cmd, void __user *arg) { struct dlci_add add; int err; diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 05aa310d3..29b82687b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -2542,7 +2542,7 @@ int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) pc300conf_t conf_aux; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; int ch = chan->channel; - void *arg = (void *) ifr->ifr_data; + void __user *arg = ifr->ifr_data; struct if_settings *settings = &ifr->ifr_settings; uclong scabase = card->hw.scabase; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index e61774aef..311ac346f 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -1342,7 +1342,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) return -EPERM; spin_lock( &nl->lock ); - flags = *(struct sbni_flags*) &ifr->ifr_data; + flags = *(struct sbni_flags*) &ifr->ifr_ifru; if( flags.fixed_rxl ) nl->delta_rxl = 0, nl->cur_rxl_index = flags.rxl; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 0abba0f12..12598181a 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1095,7 +1095,7 @@ static int sdla_open(struct net_device *dev) return(0); } -static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get) +static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, int get) { struct frad_local *flp; struct conf_data data; @@ -1193,7 +1193,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get) return(0); } -static int sdla_xfer(struct net_device *dev, struct sdla_mem *info, int read) +static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int read) { struct sdla_mem mem; char *temp; @@ -1271,7 +1271,7 @@ static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { case FRAD_GET_CONF: case FRAD_SET_CONF: - return(sdla_config(dev, (struct frad_conf *)ifr->ifr_data, cmd == FRAD_GET_CONF)); + return(sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF)); case SDLA_IDENTIFY: ifr->ifr_flags = flp->type; @@ -1306,7 +1306,7 @@ NOTE: This is rather a useless action right now, as the case SDLA_WRITEMEM: case SDLA_READMEM: - return(sdla_xfer(dev, (struct sdla_mem *)ifr->ifr_data, cmd == SDLA_READMEM)); + return(sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM)); case SDLA_START: sdla_start(dev); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index ee328d5c2..5eb32a9ca 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1841,7 +1841,7 @@ wl_his_gather(struct net_device * dev, #endif /* HISTOGRAM */ static inline int -wl_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +wl_netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; @@ -2764,7 +2764,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ switch(cmd) { case SIOCETHTOOL: - ret = wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + ret = wl_netdev_ethtool_ioctl(dev, rq->ifr_data); break; /* ------------------- OTHER IOCTL ------------------- */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index ed4acc13a..4e62fa630 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1487,7 +1487,7 @@ struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) return wstats; } -static inline int wl3501_ethtool_ioctl(struct net_device *dev, void *uaddr) +static inline int wl3501_ethtool_ioctl(struct net_device *dev, void __user *uaddr) { u32 ethcmd; int rc = -EFAULT; @@ -1532,7 +1532,7 @@ static int wl3501_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (netif_device_present(dev)) { rc = -EOPNOTSUPP; if (cmd == SIOCETHTOOL) - rc = wl3501_ethtool_ioctl(dev, (void *)rq->ifr_data); + rc = wl3501_ethtool_ioctl(dev, rq->ifr_data); } return rc; } diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 9994de2d9..81e97947c 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1405,7 +1405,7 @@ static void set_rx_mode(struct net_device *dev) outw(cfg_value | 0x1000, ioaddr + Cnfg); } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct yellowfin_private *np = dev->priv; u32 ethcmd; @@ -1433,11 +1433,11 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct yellowfin_private *np = dev->priv; long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); switch(cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(dev, rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ data->phy_id = np->phys[0] & 0x1f; /* Fall Through */ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7e93bfccb..d5d487e79 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -797,7 +797,7 @@ out: /*====================================================================*/ -static ssize_t ds_read(struct file *file, char *buf, +static ssize_t ds_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct pcmcia_bus_socket *s; @@ -819,14 +819,14 @@ static ssize_t ds_read(struct file *file, char *buf, ret = wait_event_interruptible(s->queue, !queue_empty(user)); if (ret == 0) - ret = put_user(get_queued_event(user), (int *)buf) ? -EFAULT : 4; + ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4; return ret; } /* ds_read */ /*====================================================================*/ -static ssize_t ds_write(struct file *file, const char *buf, +static ssize_t ds_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct pcmcia_bus_socket *s; @@ -849,7 +849,7 @@ static ssize_t ds_write(struct file *file, const char *buf, if (s->req_pending) { s->req_pending--; - get_user(s->req_result, (int *)buf); + get_user(s->req_result, (int __user *)buf); if ((s->req_result != 0) || (s->req_pending == 0)) wake_up_interruptible(&s->request); } else @@ -888,6 +888,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg) { struct pcmcia_bus_socket *s; + void __user *uarg = (char __user *)arg; u_int size; int ret, err; ds_ioctl_arg_t buf; @@ -911,14 +912,14 @@ static int ds_ioctl(struct inode * inode, struct file * file, return -EPERM; if (cmd & IOC_IN) { - err = verify_area(VERIFY_READ, (char *)arg, size); + err = verify_area(VERIFY_READ, uarg, size); if (err) { ds_dbg(3, "ds_ioctl(): verify_read = %d\n", err); return err; } } if (cmd & IOC_OUT) { - err = verify_area(VERIFY_WRITE, (char *)arg, size); + err = verify_area(VERIFY_WRITE, uarg, size); if (err) { ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err); return err; @@ -927,7 +928,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, err = ret = 0; - if (cmd & IOC_IN) __copy_from_user((char *)&buf, (char *)arg, size); + if (cmd & IOC_IN) __copy_from_user((char *)&buf, uarg, size); switch (cmd) { case DS_ADJUST_RESOURCE_INFO: @@ -1042,7 +1043,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, } } - if (cmd & IOC_OUT) __copy_to_user((char *)arg, (char *)&buf, size); + if (cmd & IOC_OUT) __copy_to_user(uarg, (char *)&buf, size); return err; } /* ds_ioctl */ diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index d595ba757..491d11bc8 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -113,26 +112,59 @@ static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) return 0; } -static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int lclk) +static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int clk) { struct soc_pcmcia_timing timing; int sock = skt->nr; soc_common_pcmcia_get_timing(skt, &timing); - pxa2xx_pcmcia_set_mcmem(sock, timing.mem, lclk); - pxa2xx_pcmcia_set_mcatt(sock, timing.attr, lclk); - pxa2xx_pcmcia_set_mcio(sock, timing.io, lclk); + pxa2xx_pcmcia_set_mcmem(sock, timing.mem, clk); + pxa2xx_pcmcia_set_mcatt(sock, timing.attr, clk); + pxa2xx_pcmcia_set_mcio(sock, timing.io, clk); return 0; } static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) { - unsigned int lclk = get_lclk_frequency_10khz(); - return pxa2xx_pcmcia_set_mcxx(skt, lclk); + unsigned int clk = get_memclk_frequency_10khz(); + return pxa2xx_pcmcia_set_mcxx(skt, clk); } +#ifdef CONFIG_CPU_FREQ + +static int +pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, + unsigned long val, + struct cpufreq_freqs *freqs) +{ +#warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" + switch (val) { + case CPUFREQ_PRECHANGE: + if (freqs->new > freqs->old) { + debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, " + "pre-updating\n", + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + pxa2xx_pcmcia_set_mcxx(skt, freqs->new); + } + break; + + case CPUFREQ_POSTCHANGE: + if (freqs->new < freqs->old) { + debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, " + "post-updating\n", + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + pxa2xx_pcmcia_set_mcxx(skt, freqs->new); + } + break; + } + return 0; +} +#endif + int pxa2xx_drv_pcmcia_probe(struct device *dev) { int ret; @@ -181,6 +213,9 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) /* Provide our PXA2xx specific timing routines. */ ops->set_timing = pxa2xx_pcmcia_set_timing; +#ifdef CONFIG_CPU_FREQ + ops->frequency_change = pxa2xx_pcmcia_frequency_change; +#endif ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); @@ -227,101 +262,13 @@ static struct device_driver pxa2xx_pcmcia_driver = { .bus = &platform_bus_type, }; -#ifdef CONFIG_CPU_FREQ - -/* - * When pxa2xx_pcmcia_notifier() decides that a MC{IO,MEM,ATT} adjustment (due - * to a core clock frequency change) is needed, this routine establishes - * new values consistent with the clock speed `clock'. - */ -static void pxa2xx_pcmcia_update_mcxx(unsigned int clock) -{ - struct soc_pcmcia_socket *skt; - - down(&soc_sockets_lock); - list_for_each_entry(skt, &soc_sockets, node) { - pxa2xx_pcmcia_set_mcxx(skt, clock); - } - up(&soc_sockets_lock); -} - -/* - * When changing the processor L clock frequency, it is necessary - * to adjust the MCXX timings accordingly. We've recorded the timings - * requested by Card Services, so this is just a matter of finding - * out what our current speed is, and then recomputing the new MCXX - * values. - * - * Returns: 0 on success, -1 on error - */ -static int -pxa2xx_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) -{ - struct cpufreq_freqs *freqs = data; - -#warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock" - switch (val) { - case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) { - debug( 2, "new frequency %u.%uMHz > %u.%uMHz, " - "pre-updating\n", - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - pxa2xx_pcmcia_update_mcxx(freqs->new); - } - break; - - case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) { - debug( 2, "new frequency %u.%uMHz < %u.%uMHz, " - "post-updating\n", - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - pxa2xx_pcmcia_update_mcxx(freqs->new); - } - break; - } - - return 0; -} - -static struct notifier_block pxa2xx_pcmcia_notifier_block = { - .notifier_call = pxa2xx_pcmcia_notifier -}; - -static int __init pxa2xx_pcmcia_cpufreq_init(void) -{ - int ret; - - ret = cpufreq_register_notifier(&pxa2xx_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier for PCMCIA (%d)\n", ret); - return ret; -} - -static void __exit pxa2xx_pcmcia_cpufreq_exit(void) -{ - cpufreq_unregister_notifier(&pxa2xx_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -#define pxa2xx_pcmcia_cpufreq_init() -#define pxa2xx_pcmcia_cpufreq_exit() -#endif - static int __init pxa2xx_pcmcia_init(void) { - int ret = driver_register(&pxa2xx_pcmcia_driver); - if (ret == 0) - pxa2xx_pcmcia_cpufreq_init(); - return ret; + return driver_register(&pxa2xx_pcmcia_driver); } static void __exit pxa2xx_pcmcia_exit(void) { - pxa2xx_pcmcia_cpufreq_exit(); driver_unregister(&pxa2xx_pcmcia_driver); } diff --git a/drivers/pcmcia/pxa2xx_base.h b/drivers/pcmcia/pxa2xx_base.h new file mode 100644 index 000000000..e46cff345 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_base.h @@ -0,0 +1,3 @@ +/* temporary measure */ +extern int pxa2xx_drv_pcmcia_probe(struct device *); + diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index c18f28605..e22a57a4a 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "sa1111_generic.h" diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index fb634ab5d..db04ffb6f 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -111,6 +110,32 @@ sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock) return 0; } +#ifdef CONFIG_CPU_FREQ +static int +sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, + unsigned long val, + struct cpufreq_freqs *freqs) +{ + switch (val) { + case CPUFREQ_PRECHANGE: + if (freqs->new > freqs->old) + sa1100_pcmcia_set_mecr(skt, freqs->new); + break; + + case CPUFREQ_POSTCHANGE: + if (freqs->new < freqs->old) + sa1100_pcmcia_set_mecr(skt, freqs->new); + break; + case CPUFREQ_RESUMECHANGE: + sa1100_pcmcia_set_mecr(skt, freqs->new); + break; + } + + return 0; +} + +#endif + static int sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt) { @@ -152,90 +177,23 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, /* Provide our SA11x0 specific timing routines. */ ops->set_timing = sa1100_pcmcia_set_timing; ops->show_timing = sa1100_pcmcia_show_timing; +#ifdef CONFIG_CPU_FREQ + ops->frequency_change = sa1100_pcmcia_frequency_change; +#endif return soc_common_drv_pcmcia_probe(dev, ops, first, nr); } EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); -#ifdef CONFIG_CPU_FREQ - -/* sa1100_pcmcia_update_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due - * to a core clock frequency change) is needed, this routine establishes - * new BS_xx values consistent with the clock speed `clock'. - */ -static void sa1100_pcmcia_update_mecr(unsigned int clock) -{ - struct soc_pcmcia_socket *skt; - - down(&soc_pcmcia_sockets_lock); - list_for_each_entry(skt, &soc_pcmcia_sockets, node) - sa1100_pcmcia_set_mecr(skt, clock); - up(&soc_pcmcia_sockets_lock); -} - -/* sa1100_pcmcia_notifier() - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * When changing the processor core clock frequency, it is necessary - * to adjust the MECR timings accordingly. We've recorded the timings - * requested by Card Services, so this is just a matter of finding - * out what our current speed is, and then recomputing the new MECR - * values. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freqs = data; - - switch (val) { - case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) - sa1100_pcmcia_update_mecr(freqs->new); - break; - - case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) - sa1100_pcmcia_update_mecr(freqs->new); - break; - case CPUFREQ_RESUMECHANGE: - sa1100_pcmcia_update_mecr(freqs->new); - break; - } - - return 0; -} - -static struct notifier_block sa1100_pcmcia_notifier_block = { - .notifier_call = sa1100_pcmcia_notifier -}; - static int __init sa11xx_pcmcia_init(void) { - int ret; - - printk(KERN_INFO "SA11xx PCMCIA\n"); - - ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier (%d)\n", ret); - - return ret; + return 0; } module_init(sa11xx_pcmcia_init); -static void __exit sa11xx_pcmcia_exit(void) -{ - cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -} +static void __exit sa11xx_pcmcia_exit(void) {} module_exit(sa11xx_pcmcia_exit); -#endif MODULE_AUTHOR("John Dorsey "); MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index ff8b52124..6d393e739 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -31,6 +31,7 @@ ======================================================================*/ +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include @@ -614,6 +616,49 @@ struct skt_dev_info { #define SKT_DEV_INFO_SIZE(n) \ (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) +#ifdef CONFIG_CPU_FREQ +static int +soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + struct soc_pcmcia_socket *skt; + struct cpufreq_freqs *freqs = data; + int ret = 0; + + down(&soc_pcmcia_sockets_lock); + list_for_each_entry(skt, &soc_pcmcia_sockets, node) + if ( skt->ops->frequency_change ) + ret += skt->ops->frequency_change(skt, val, freqs); + up(&soc_pcmcia_sockets_lock); + + return ret; +} + +static struct notifier_block soc_pcmcia_notifier_block = { + .notifier_call = soc_pcmcia_notifier +}; + +static int soc_pcmcia_cpufreq_register(void) +{ + int ret; + + ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + if (ret < 0) + printk(KERN_ERR "Unable to register CPU frequency change " + "notifier for PCMCIA (%d)\n", ret); + return ret; +} + +static void soc_pcmcia_cpufreq_unregister(void) +{ + cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +#define soc_pcmcia_cpufreq_register() +#define soc_pcmcia_cpufreq_unregister() +#endif + int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) { struct skt_dev_info *sinfo; @@ -692,6 +737,9 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops goto out_err_5; } + if ( list_empty(&soc_pcmcia_sockets) ) + soc_pcmcia_cpufreq_register(); + list_add(&skt->node, &soc_pcmcia_sockets); /* @@ -789,6 +837,9 @@ int soc_common_drv_pcmcia_remove(struct device *dev) release_resource(&skt->res_io); release_resource(&skt->res_skt); } + if ( list_empty(&soc_pcmcia_sockets) ) + soc_pcmcia_cpufreq_unregister(); + up(&soc_pcmcia_sockets_lock); kfree(sinfo); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index b0d716ef0..767b2c1a2 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1078,6 +1078,7 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1620, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 0a94ee9db..cf54b0a36 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -55,7 +55,7 @@ static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) return (file->f_pos = new); } -static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { struct inode *ino = file->f_dentry->d_inode; struct proc_dir_entry *dp = PDE(ino); diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index 063ae5ecf..88fcd1668 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -176,7 +176,7 @@ static int proc_read_node(char *buf, char **start, off_t pos, return len; } -static int proc_write_node(struct file *file, const char *buf, +static int proc_write_node(struct file *file, const char __user *buf, unsigned long count, void *data) { struct pnp_bios_node *node; diff --git a/drivers/s390/block/dasd_cmb.c b/drivers/s390/block/dasd_cmb.c index 8139ffddc..ed1ab474c 100644 --- a/drivers/s390/block/dasd_cmb.c +++ b/drivers/s390/block/dasd_cmb.c @@ -58,7 +58,7 @@ static int dasd_ioctl_readall_cmb(struct block_device *bdev, int no, long args) { struct dasd_device *device; - struct cmbdata * __user udata; + struct cmbdata __user *udata; struct cmbdata data; size_t size; int ret; @@ -66,7 +66,7 @@ dasd_ioctl_readall_cmb(struct block_device *bdev, int no, long args) device = bdev->bd_disk->private_data; if (!device) return -EINVAL; - udata = (void *) args; + udata = (void __user *) args; size = _IOC_SIZE(no); if (!access_ok(VERIFY_WRITE, udata, size)) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 67a896cd4..888aeb399 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.34 $ + * $Revision: 1.36 $ */ #include @@ -35,6 +35,8 @@ MODULE_LICENSE("GPL"); +struct dasd_discipline dasd_diag_discipline; + struct dasd_diag_private { struct dasd_diag_characteristics rdc_data; struct dasd_diag_rw_io iob; @@ -292,7 +294,7 @@ dasd_diag_check_device(struct dasd_device *device) mdsk_term_io(device); } if (bsize <= PAGE_SIZE && label[3] == bsize && - label[0] == 0xc3d4e2f1 && label[13] != 0) { + label[0] == 0xc3d4e2f1) { device->blocks = label[7]; device->bp_block = bsize; device->s2b_shift = 0; /* bits to shift 512 to get a block */ @@ -489,6 +491,7 @@ dasd_diag_init(void) ctl_set_bit(0, 9); register_external_interrupt(0x2603, dasd_ext_handler); + dasd_diag_discipline_pointer = &dasd_diag_discipline; return 0; } @@ -503,6 +506,7 @@ dasd_diag_cleanup(void) } unregister_external_interrupt(0x2603, dasd_ext_handler); ctl_clear_bit(0, 9); + dasd_diag_discipline_pointer = NULL; } module_init(dasd_diag_init); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 9967c082c..b222f9503 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.57 $ + * $Revision: 1.58 $ */ #ifndef DASD_INT_H @@ -260,12 +260,7 @@ struct dasd_discipline { int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); }; -extern struct dasd_discipline dasd_diag_discipline; -#ifdef CONFIG_DASD_DIAG -#define dasd_diag_discipline_pointer (&dasd_diag_discipline) -#else -#define dasd_diag_discipline_pointer (0) -#endif +extern struct dasd_discipline *dasd_diag_discipline_pointer; struct dasd_device { /* Block device stuff. */ diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 3efdcad25..8cbddce1f 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -120,7 +120,7 @@ static int dasd_ioctl_api_version(struct block_device *bdev, int no, long args) { int ver = DASD_API_VERSION; - return put_user(ver, (int *) args); + return put_user(ver, (int __user *) args); } /* @@ -305,7 +305,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) return -ENODEV; if (test_bit(DASD_FLAG_RO, &device->flags)) return -EROFS; - if (copy_from_user(&fdata, (void *) args, + if (copy_from_user(&fdata, (void __user *) args, sizeof (struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { @@ -348,7 +348,7 @@ dasd_ioctl_read_profile(struct block_device *bdev, int no, long args) if (device == NULL) return -ENODEV; - if (copy_to_user((long *) args, (long *) &device->profile, + if (copy_to_user((long __user *) args, (long *) &device->profile, sizeof (struct dasd_profile_info_t))) return -EFAULT; return 0; @@ -441,9 +441,9 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); } - + rc = 0; - if (copy_to_user((long *) args, (long *) dasd_info, + if (copy_to_user((long __user *) args, (long *) dasd_info, ((no == (unsigned int) BIODASDINFO2) ? sizeof (struct dasd_information2_t) : sizeof (struct dasd_information_t)))) @@ -466,7 +466,7 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) if (bdev != bdev->bd_contains) // ro setting is not allowed for partitions return -EINVAL; - if (get_user(intval, (int *) args)) + if (get_user(intval, (int __user *) args)) return -EFAULT; device = bdev->bd_disk->private_data; if (device == NULL) @@ -499,7 +499,7 @@ dasd_ioctl_getgeo(struct block_device *bdev, int no, long args) geo = (struct hd_geometry) {}; device->discipline->fill_geometry(device, &geo); geo.start = get_start_sect(bdev) >> device->s2b_shift; - if (copy_to_user((struct hd_geometry *) args, &geo, + if (copy_to_user((struct hd_geometry __user *) args, &geo, sizeof (struct hd_geometry))) return -EFAULT; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 70d6136d7..7cbc854cf 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -30,7 +30,7 @@ static struct proc_dir_entry *dasd_devices_entry = NULL; static struct proc_dir_entry *dasd_statistics_entry = NULL; static inline char * -dasd_get_user_string(const char *user_buf, size_t user_len) +dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; @@ -239,7 +239,7 @@ dasd_statistics_read(char *page, char **start, off_t off, } static int -dasd_statistics_write(struct file *file, const char *user_buf, +dasd_statistics_write(struct file *file, const char __user *user_buf, unsigned long user_len, void *data) { #ifdef CONFIG_DASD_PROFILE diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 8a30b5250..ca83f9b0a 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -76,8 +76,7 @@ struct dcssblk_dev_info { }; static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices); -static rwlock_t dcssblk_devices_lock = RW_LOCK_UNLOCKED; - +static struct rw_semaphore dcssblk_devices_sem; /* * release function for segment device. @@ -92,8 +91,8 @@ dcssblk_release_segment(struct device *dev) /* * get a minor number. needs to be called with - * write_lock(&dcssblk_devices_lock) and the - * device needs to be enqueued before the lock is + * down_write(&dcssblk_devices_sem) and the + * device needs to be enqueued before the semaphore is * freed. */ static inline int @@ -121,7 +120,7 @@ dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) /* * get the struct dcssblk_dev_info from dcssblk_devices * for the given name. - * read_lock(&dcssblk_devices_lock) must be held. + * down_read(&dcssblk_devices_sem) must be held. */ static struct dcssblk_dev_info * dcssblk_get_device_by_name(char *name) @@ -136,31 +135,6 @@ dcssblk_get_device_by_name(char *name) return NULL; } -/* - * register the device that represents a segment in sysfs, - * also add the attributes for the device - */ -static inline int -dcssblk_register_segment_device(struct device *dev) -{ - int rc; - - rc = device_register(dev); - if (rc) - return rc; - rc = device_create_file(dev, &dev_attr_shared); - if (rc) - goto unregister_dev; - rc = device_create_file(dev, &dev_attr_save); - if (rc) - goto unregister_dev; - return rc; - -unregister_dev: - device_unregister(dev); - return rc; -} - /* * device attribute for switching shared/nonshared (exclusive) * operation (show + store) @@ -184,24 +158,24 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; } - write_lock(&dcssblk_devices_lock); + down_write(&dcssblk_devices_sem); dev_info = container_of(dev, struct dcssblk_dev_info, dev); if (atomic_read(&dev_info->use_count)) { PRINT_ERR("share: segment %s is busy!\n", dev_info->segment_name); - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); return -EBUSY; } if ((inbuf[0] == '1') && (dev_info->is_shared == 1)) { PRINT_WARN("Segment %s already loaded in shared mode!\n", dev_info->segment_name); - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); return count; } if ((inbuf[0] == '0') && (dev_info->is_shared == 0)) { PRINT_WARN("Segment %s already loaded in exclusive mode!\n", dev_info->segment_name); - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); return count; } if (inbuf[0] == '1') { @@ -231,7 +205,7 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) PRINT_INFO("Segment %s reloaded, exclusive (read-write) mode.\n", dev_info->segment_name); } else { - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; } @@ -262,14 +236,13 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) dev_info->segment_name); rc = -EPERM; } - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); goto out; removeseg: PRINT_ERR("Could not reload segment %s, removing it now!\n", dev_info->segment_name); list_del(&dev_info->lh); - write_unlock(&dcssblk_devices_lock); del_gendisk(dev_info->gd); blk_put_queue(dev_info->dcssblk_queue); @@ -277,6 +250,7 @@ removeseg: put_disk(dev_info->gd); device_unregister(dev); put_device(dev); + up_write(&dcssblk_devices_sem); out: return rc; } @@ -308,7 +282,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) } dev_info = container_of(dev, struct dcssblk_dev_info, dev); - write_lock(&dcssblk_devices_lock); + down_write(&dcssblk_devices_sem); if (inbuf[0] == '1') { if (atomic_read(&dev_info->use_count) == 0) { // device is idle => we save immediately @@ -332,11 +306,11 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) dev_info->segment_name); } } else { - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; } - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); return count; } @@ -375,9 +349,9 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) /* * already loaded? */ - read_lock(&dcssblk_devices_lock); + down_read(&dcssblk_devices_sem); dev_info = dcssblk_get_device_by_name(local_buf); - read_unlock(&dcssblk_devices_lock); + up_read(&dcssblk_devices_sem); if (dev_info != NULL) { PRINT_WARN("Segment %s already loaded!\n", local_buf); rc = -EEXIST; @@ -433,10 +407,10 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) /* * get minor, add to list */ - write_lock(&dcssblk_devices_lock); + down_write(&dcssblk_devices_sem); rc = dcssblk_assign_free_minor(dev_info); if (rc) { - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); PRINT_ERR("No free minor number available! " "Unloading segment...\n"); goto unload_seg; @@ -444,22 +418,29 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) sprintf(dev_info->gd->disk_name, "dcssblk%d", dev_info->gd->first_minor); list_add_tail(&dev_info->lh, &dcssblk_devices); + + if (!try_module_get(THIS_MODULE)) { + rc = -ENODEV; + goto list_del; + } /* * register the device */ - rc = dcssblk_register_segment_device(&dev_info->dev); + rc = device_register(&dev_info->dev); if (rc) { PRINT_ERR("Segment %s could not be registered RC=%d\n", local_buf, rc); + module_put(THIS_MODULE); goto list_del; } - - if (!try_module_get(THIS_MODULE)) { - rc = -ENODEV; - goto list_del; - } - get_device(&dev_info->dev); + rc = device_create_file(&dev_info->dev, &dev_attr_shared); + if (rc) + goto unregister_dev; + rc = device_create_file(&dev_info->dev, &dev_attr_save); + if (rc) + goto unregister_dev; + add_disk(dev_info->gd); blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); @@ -476,13 +457,24 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) break; } PRINT_DEBUG("Segment %s loaded successfully\n", local_buf); - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); rc = count; goto out; +unregister_dev: + PRINT_ERR("device_create_file() failed!\n"); + list_del(&dev_info->lh); + blk_put_queue(dev_info->dcssblk_queue); + dev_info->gd->queue = NULL; + put_disk(dev_info->gd); + device_unregister(&dev_info->dev); + segment_unload(dev_info->segment_name); + put_device(&dev_info->dev); + up_write(&dcssblk_devices_sem); + goto out; list_del: list_del(&dev_info->lh); - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); unload_seg: segment_unload(local_buf); dealloc_gendisk: @@ -526,22 +518,21 @@ dcssblk_remove_store(struct device *dev, const char *buf, size_t count) goto out_buf; } - write_lock(&dcssblk_devices_lock); + down_write(&dcssblk_devices_sem); dev_info = dcssblk_get_device_by_name(local_buf); if (dev_info == NULL) { - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); PRINT_WARN("Segment %s is not loaded!\n", local_buf); rc = -ENODEV; goto out_buf; } if (atomic_read(&dev_info->use_count) != 0) { - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); PRINT_WARN("Segment %s is in use!\n", local_buf); rc = -EBUSY; goto out_buf; } list_del(&dev_info->lh); - write_unlock(&dcssblk_devices_lock); del_gendisk(dev_info->gd); blk_put_queue(dev_info->dcssblk_queue); @@ -552,6 +543,8 @@ dcssblk_remove_store(struct device *dev, const char *buf, size_t count) PRINT_DEBUG("Segment %s unloaded successfully\n", dev_info->segment_name); put_device(&dev_info->dev); + up_write(&dcssblk_devices_sem); + rc = count; out_buf: kfree(local_buf); @@ -587,7 +580,7 @@ dcssblk_release(struct inode *inode, struct file *filp) rc = -ENODEV; goto out; } - write_lock(&dcssblk_devices_lock); + down_write(&dcssblk_devices_sem); if (atomic_dec_and_test(&dev_info->use_count) && (dev_info->save_pending)) { PRINT_INFO("Segment %s became idle and is being saved now\n", @@ -595,7 +588,7 @@ dcssblk_release(struct inode *inode, struct file *filp) segment_replace(dev_info->segment_name); dev_info->save_pending = 0; } - write_unlock(&dcssblk_devices_lock); + up_write(&dcssblk_devices_sem); rc = 0; out: return rc; @@ -616,7 +609,7 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio) dev_info = bio->bi_bdev->bd_disk->private_data; if (dev_info == NULL) goto fail; - if ((bio->bi_sector & 3) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; if (((bio->bi_size >> 9) + bio->bi_sector) @@ -695,6 +688,7 @@ dcssblk_init(void) return rc; } dcssblk_major = rc; + init_rwsem(&dcssblk_devices_sem); PRINT_DEBUG("...finished!\n"); return 0; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 00885b09f..312057e93 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -155,7 +155,7 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index) { int cc; - __asm__ __volatile( + __asm__ __volatile__ ( " lhi %0,2\n" /* return unused cc 2 if pgin traps */ " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */ "0: ipm %0\n" @@ -203,7 +203,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) { int cc; - __asm__ __volatile( + __asm__ __volatile__ ( " lhi %0,2\n" /* return unused cc 2 if pgout traps */ " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */ "0: ipm %0\n" @@ -290,7 +290,7 @@ static int xpram_make_request(request_queue_t *q, struct bio *bio) unsigned long bytes; int i; - if ((bio->bi_sector & 3) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; if ((bio->bi_size >> 12) > xdev->size) @@ -332,16 +332,16 @@ fail: static int xpram_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - struct hd_geometry *geo; + struct hd_geometry __user *geo; unsigned long size; - if (cmd != HDIO_GETGEO) + if (cmd != HDIO_GETGEO) return -EINVAL; /* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ - geo = (struct hd_geometry *) arg; + geo = (struct hd_geometry __user *) arg; size = (xpram_pages * 8) & ~0x3f; put_user(size >> 6, &geo->cylinders); put_user(4, &geo->heads); @@ -423,7 +423,7 @@ static int __init xpram_setup_sizes(unsigned long pages) return 0; } -static struct request_queue xpram_queue; +static struct request_queue *xpram_queue; static int __init xpram_setup_blkdev(void) { @@ -450,8 +450,13 @@ static int __init xpram_setup_blkdev(void) * Assign the other needed values: make request function, sizes and * hardsect size. All the minor devices feature the same value. */ - blk_queue_make_request(&xpram_queue, xpram_make_request); - blk_queue_hardsect_size(&xpram_queue, 4096); + xpram_queue = blk_alloc_queue(GFP_KERNEL); + if (!xpram_queue) { + rc = -ENOMEM; + goto out_unreg; + } + blk_queue_make_request(xpram_queue, xpram_make_request); + blk_queue_hardsect_size(xpram_queue, 4096); /* * Setup device structures. @@ -467,7 +472,7 @@ static int __init xpram_setup_blkdev(void) disk->first_minor = i; disk->fops = &xpram_devops; disk->private_data = &xpram_devices[i]; - disk->queue = &xpram_queue; + disk->queue = xpram_queue; sprintf(disk->disk_name, "slram%d", i); sprintf(disk->devfs_name, "slram/%d", i); set_capacity(disk, xpram_sizes[i] << 1); @@ -475,6 +480,9 @@ static int __init xpram_setup_blkdev(void) } return 0; +out_unreg: + devfs_remove("slram"); + unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); out: while (i--) put_disk(xpram_disks[i]); @@ -493,6 +501,7 @@ static void __exit xpram_exit(void) } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); devfs_remove("slram"); + blk_cleanup_queue(xpram_queue); sysdev_unregister(&xpram_sys_device); sysdev_class_unregister(&xpram_sysclass); } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 0e724c813..e92bb9473 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1002,7 +1002,8 @@ tty3215_write(struct tty_struct * tty, int from_user, ret = 0; while (count > 0) { length = count < 80 ? count : 80; - length -= copy_from_user(raw->ubuffer, buf, length); + length -= copy_from_user(raw->ubuffer, + (const unsigned char __user *)buf, length); if (length == 0) { if (!ret) ret = -EFAULT; diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index b124ebb7f..5e35728db 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -338,7 +338,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) * Ioctl stuff. */ static int -do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry *user_kbe, +do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe, int cmd, int perm) { struct kbentry tmp; @@ -410,7 +410,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry *user_kbe, } static int -do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry *u_kbs, +do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, int cmd, int perm) { unsigned char kb_func; @@ -464,9 +464,12 @@ int kbd_ioctl(struct kbd_data *kbd, struct file *file, unsigned int cmd, unsigned long arg) { - struct kbdiacrs *a; + struct kbdiacrs __user *a; + void __user *argp; int ct, perm; + argp = (void __user *)arg; + /* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. @@ -474,15 +477,15 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file, perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); switch (cmd) { case KDGKBTYPE: - return put_user(KB_101, (char*) arg); + return put_user(KB_101, (char __user *)argp); case KDGKBENT: case KDSKBENT: - return do_kdsk_ioctl(kbd, (struct kbentry *)arg, cmd, perm); + return do_kdsk_ioctl(kbd, argp, cmd, perm); case KDGKBSENT: case KDSKBSENT: - return do_kdgkb_ioctl(kbd, (struct kbsentry *)arg, cmd, perm); + return do_kdgkb_ioctl(kbd, argp, cmd, perm); case KDGKBDIACR: - a = (struct kbdiacrs *) arg; + a = argp; if (put_user(kbd->accent_table_size, &a->kb_cnt)) return -EFAULT; @@ -492,7 +495,7 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file, return -EFAULT; return 0; case KDSKBDIACR: - a = (struct kbdiacrs *) arg; + a = argp; if (!perm) return -EPERM; if (get_user(ct, &a->kb_cnt)) diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 1035707f8..a1ad37580 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -112,46 +112,46 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { case TIOCSCLPSHTAB: /* set width of horizontal tab */ - if (get_user(sclp_ioctls.htab, (unsigned short *) arg)) + if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg)) rc = -EFAULT; else check = 1; break; case TIOCSCLPGHTAB: /* get width of horizontal tab */ - if (put_user(sclp_ioctls.htab, (unsigned short *) arg)) + if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSECHO: /* enable/disable echo of input */ - if (get_user(sclp_ioctls.echo, (unsigned char *) arg)) + if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPGECHO: /* Is echo of input enabled ? */ - if (put_user(sclp_ioctls.echo, (unsigned char *) arg)) + if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSCOLS: /* set number of columns for output */ - if (get_user(sclp_ioctls.columns, (unsigned short *) arg)) + if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg)) rc = -EFAULT; else check = 1; break; case TIOCSCLPGCOLS: /* get number of columns for output */ - if (put_user(sclp_ioctls.columns, (unsigned short *) arg)) + if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSNL: /* enable/disable writing without final new line character */ - if (get_user(sclp_ioctls.final_nl, (signed char *) arg)) + if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPGNL: /* Is writing without final new line character enabled ? */ - if (put_user(sclp_ioctls.final_nl, (signed char *) arg)) + if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSOBUF: @@ -160,7 +160,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file, * up to next 4kB boundary and stored as number of SCCBs * (4kB Buffers) limitation: 256 x 4kB */ - if (get_user(obuf, (unsigned int *) arg) == 0) { + if (get_user(obuf, (unsigned int __user *) arg) == 0) { if (obuf & 0xFFF) sclp_ioctls.max_sccb = (obuf >> 12) + 1; else @@ -171,22 +171,22 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file, case TIOCSCLPGOBUF: /* get the maximum buffers size for output */ obuf = sclp_ioctls.max_sccb << 12; - if (put_user(obuf, (unsigned int *) arg)) + if (put_user(obuf, (unsigned int __user *) arg)) rc = -EFAULT; break; case TIOCSCLPGKBUF: /* get the number of buffers got from kernel at startup */ - if (put_user(sclp_ioctls.kmem_sccb, (unsigned short *) arg)) + if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSCASE: /* enable/disable conversion from upper to lower case */ - if (get_user(sclp_ioctls.tolower, (unsigned char *) arg)) + if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPGCASE: /* Is conversion from upper to lower case of input enabled? */ - if (put_user(sclp_ioctls.tolower, (unsigned char *) arg)) + if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSDELIM: @@ -194,7 +194,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file, * set special character used for separating upper and * lower case, 0x00 disables this feature */ - if (get_user(sclp_ioctls.delim, (unsigned char *) arg)) + if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPGDELIM: @@ -202,7 +202,7 @@ sclp_tty_ioctl(struct tty_struct *tty, struct file * file, * get special character used for separating upper and * lower case, 0x00 disables this feature */ - if (put_user(sclp_ioctls.delim, (unsigned char *) arg)) + if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg)) rc = -EFAULT; break; case TIOCSCLPSINIT: @@ -415,7 +415,8 @@ sclp_tty_write(struct tty_struct *tty, int from_user, while (count > 0) { length = count < SCLP_TTY_BUF_SIZE ? count : SCLP_TTY_BUF_SIZE; - length -= copy_from_user(sclp_tty_chars, buf, length); + length -= copy_from_user(sclp_tty_chars, + (const unsigned char __user *)buf, length); if (length == 0) { if (!ret) ret = -EFAULT; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 32d439726..22760a120 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -490,7 +490,8 @@ sclp_vt220_write(struct tty_struct *tty, int from_user, while (count > 0) { length = count < SCLP_VT220_BUF_SIZE ? count : SCLP_VT220_BUF_SIZE; - length -= copy_from_user(tty->driver_data, buf, length); + length -= copy_from_user(tty->driver_data, + (const unsigned char __user *)buf, length); if (length == 0) { if (!ret) return -EFAULT; diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index 272bd1c75..d04e6c2c3 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -32,7 +32,7 @@ struct gendisk; #ifdef DBF_LIKE_HELL #define DBF_LH(level, str, ...) \ do { \ - debug_sprintf_event(tape_dbf_area, level, str, ## __VA_ARGS__); \ + debug_sprintf_event(TAPE_DBF_AREA, level, str, ## __VA_ARGS__); \ } while (0) #else #define DBF_LH(level, str, ...) do {} while(0) @@ -43,12 +43,12 @@ do { \ */ #define DBF_EVENT(d_level, d_str...) \ do { \ - debug_sprintf_event(tape_dbf_area, d_level, d_str); \ + debug_sprintf_event(TAPE_DBF_AREA, d_level, d_str); \ } while (0) #define DBF_EXCEPTION(d_level, d_str...) \ do { \ - debug_sprintf_exception(tape_dbf_area, d_level, d_str); \ + debug_sprintf_exception(TAPE_DBF_AREA, d_level, d_str); \ } while (0) #define TAPE_VERSION_MAJOR 2 @@ -313,7 +313,7 @@ extern void tape_dump_sense_dbf(struct tape_device *, struct tape_request *, extern void tape_med_state_set(struct tape_device *, enum tape_medium_state); /* The debug area */ -extern debug_info_t *tape_dbf_area; +extern debug_info_t *TAPE_DBF_AREA; /* functions for building ccws */ static inline struct ccw1 * diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index e738c4d37..480ec8797 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -15,11 +15,19 @@ #include #include +#define TAPE_DBF_AREA tape_34xx_dbf + #include "tape.h" #include "tape_std.h" #define PRINTK_HEADER "TAPE_34XX: " +/* + * Pointer to debug area. + */ +debug_info_t *TAPE_DBF_AREA = NULL; +EXPORT_SYMBOL(TAPE_DBF_AREA); + enum tape_34xx_type { tape_3480, tape_3490, @@ -885,7 +893,7 @@ tape_34xx_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg) if (cmd == TAPE390_DISPLAY) { struct display_struct disp; - if (copy_from_user(&disp, (char *) arg, sizeof(disp)) != 0) + if (copy_from_user(&disp, (char __user *) arg, sizeof(disp)) != 0) return -EFAULT; return tape_std_display(device, &disp); @@ -1343,7 +1351,13 @@ tape_34xx_init (void) { int rc; - DBF_EVENT(3, "34xx init: $Revision: 1.20 $\n"); + TAPE_DBF_AREA = debug_register ( "tape_34xx", 1, 2, 4*sizeof(long)); + debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); +#ifdef DBF_LIKE_HELL + debug_set_level(TAPE_DBF_AREA, 6); +#endif + + DBF_EVENT(3, "34xx init: $Revision: 1.21 $\n"); /* Register driver for 3480/3490 tapes. */ rc = ccw_driver_register(&tape_34xx_driver); if (rc) @@ -1357,12 +1371,14 @@ static void tape_34xx_exit(void) { ccw_driver_unregister(&tape_34xx_driver); + + debug_unregister(TAPE_DBF_AREA); } MODULE_DEVICE_TABLE(ccw, tape_34xx_ids); MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH"); MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape " - "device driver ($Revision: 1.20 $)"); + "device driver ($Revision: 1.21 $)"); MODULE_LICENSE("GPL"); module_init(tape_34xx_init); diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 7f4ab64c1..b7f4e7b8b 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -19,6 +19,8 @@ #include +#define TAPE_DBF_AREA tape_core_dbf + #include "tape.h" #define PRINTK_HEADER "TAPE_BLOCK: " diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index ccbe214d7..0d0343b87 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -18,6 +18,8 @@ #include +#define TAPE_DBF_AREA tape_core_dbf + #include "tape.h" #include "tape_std.h" #include "tape_class.h" @@ -29,8 +31,8 @@ /* * file operation structure for tape character frontend */ -static ssize_t tapechar_read(struct file *, char *, size_t, loff_t *); -static ssize_t tapechar_write(struct file *, const char *, size_t, loff_t *); +static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *); static int tapechar_open(struct inode *,struct file *); static int tapechar_release(struct inode *,struct file *); static int tapechar_ioctl(struct inode *, struct file *, unsigned int, @@ -134,7 +136,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) * Tape device read function */ ssize_t -tapechar_read (struct file *filp, char *data, size_t count, loff_t *ppos) +tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; struct tape_request *request; @@ -208,7 +210,7 @@ tapechar_read (struct file *filp, char *data, size_t count, loff_t *ppos) * Tape device write function */ ssize_t -tapechar_write(struct file *filp, const char *data, size_t count, loff_t *ppos) +tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; struct tape_request *request; @@ -389,7 +391,7 @@ tapechar_ioctl(struct inode *inp, struct file *filp, if (no == MTIOCTOP) { struct mtop op; - if (copy_from_user(&op, (char *) data, sizeof(op)) != 0) + if (copy_from_user(&op, (char __user *) data, sizeof(op)) != 0) return -EFAULT; if (op.mt_count < 0) return -EINVAL; @@ -436,7 +438,7 @@ tapechar_ioctl(struct inode *inp, struct file *filp, if (rc < 0) return rc; pos.mt_blkno = rc; - if (copy_to_user((char *) data, &pos, sizeof(pos)) != 0) + if (copy_to_user((char __user *) data, &pos, sizeof(pos)) != 0) return -EFAULT; return 0; } @@ -466,7 +468,7 @@ tapechar_ioctl(struct inode *inp, struct file *filp, get.mt_blkno = rc; } - if (copy_to_user((char *) data, &get, sizeof(get)) != 0) + if (copy_to_user((char __user *) data, &get, sizeof(get)) != 0) return -EFAULT; return 0; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 6d7c5c0f2..668fe3f11 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -20,6 +20,8 @@ #include // for variable types +#define TAPE_DBF_AREA tape_core_dbf + #include "tape.h" #include "tape_std.h" @@ -39,7 +41,8 @@ static rwlock_t tape_device_lock = RW_LOCK_UNLOCKED; /* * Pointer to debug area. */ -debug_info_t *tape_dbf_area = NULL; +debug_info_t *TAPE_DBF_AREA = NULL; +EXPORT_SYMBOL(TAPE_DBF_AREA); /* * Printable strings for tape enumerations. @@ -1176,12 +1179,12 @@ tape_mtop(struct tape_device *device, int mt_op, int mt_count) static int tape_init (void) { - tape_dbf_area = debug_register ( "tape", 1, 2, 4*sizeof(long)); - debug_register_view(tape_dbf_area, &debug_sprintf_view); + TAPE_DBF_AREA = debug_register ( "tape", 1, 2, 4*sizeof(long)); + debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); #ifdef DBF_LIKE_HELL - debug_set_level(tape_dbf_area, 6); + debug_set_level(TAPE_DBF_AREA, 6); #endif - DBF_EVENT(3, "tape init: ($Revision: 1.49 $)\n"); + DBF_EVENT(3, "tape init: ($Revision: 1.50 $)\n"); tape_proc_init(); tapechar_init (); tapeblock_init (); @@ -1200,19 +1203,18 @@ tape_exit(void) tapechar_exit(); tapeblock_exit(); tape_proc_cleanup(); - debug_unregister (tape_dbf_area); + debug_unregister (TAPE_DBF_AREA); } MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and " "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)"); MODULE_DESCRIPTION("Linux on zSeries channel attached " - "tape device driver ($Revision: 1.49 $)"); + "tape device driver ($Revision: 1.50 $)"); MODULE_LICENSE("GPL"); module_init(tape_init); module_exit(tape_exit); -EXPORT_SYMBOL(tape_dbf_area); EXPORT_SYMBOL(tape_generic_remove); EXPORT_SYMBOL(tape_generic_probe); EXPORT_SYMBOL(tape_generic_online); diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 11d56de8d..801d17cca 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -16,6 +16,8 @@ #include #include +#define TAPE_DBF_AREA tape_core_dbf + #include "tape.h" #define PRINTK_HEADER "TAPE_PROC: " diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index afa014fe8..2f9fe3098 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -22,6 +22,8 @@ #include #include +#define TAPE_DBF_AREA tape_core_dbf + #include "tape.h" #include "tape_std.h" diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 71c03c87e..3720e77b4 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -2,7 +2,7 @@ * drivers/s390/cio/airq.c * S/390 common I/O routines -- support for adapter interruptions * - * $Revision: 1.11 $ + * $Revision: 1.12 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -14,11 +14,11 @@ #include #include #include +#include #include "cio_debug.h" #include "airq.h" -static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED; static adapter_int_handler_t adapter_handler; /* @@ -40,23 +40,17 @@ s390_register_adapter_interrupt (adapter_int_handler_t handler) CIO_TRACE_EVENT (4, "rgaint"); - spin_lock (&adapter_lock); - if (handler == NULL) ret = -EINVAL; - else if (adapter_handler) - ret = -EBUSY; - else { - adapter_handler = handler; - ret = 0; - } - - spin_unlock (&adapter_lock); + else + ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0); + if (!ret) + synchronize_kernel(); sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (4, dbf_txt); - return (ret); + return ret; } int @@ -67,38 +61,26 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler) CIO_TRACE_EVENT (4, "urgaint"); - spin_lock (&adapter_lock); - if (handler == NULL) ret = -EINVAL; - else if (handler != adapter_handler) - ret = -EINVAL; else { adapter_handler = NULL; + synchronize_kernel(); ret = 0; } - - spin_unlock (&adapter_lock); - sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (4, dbf_txt); - return (ret); + return ret; } void do_adapter_IO (void) { - CIO_TRACE_EVENT (4, "doaio"); - - spin_lock (&adapter_lock); + CIO_TRACE_EVENT (6, "doaio"); if (adapter_handler) (*adapter_handler) (); - - spin_unlock (&adapter_lock); - - return; } EXPORT_SYMBOL (s390_register_adapter_interrupt); diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 0589933b9..29000d5e7 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -308,7 +308,7 @@ static int cio_ignore_read (char *page, char **start, off_t off, return len; } -static int cio_ignore_write (struct file *file, const char *user_buf, +static int cio_ignore_write(struct file *file, const char __user *user_buf, unsigned long user_len, void *data) { char *buf; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 6d0179f6a..9b86522fb 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.27 $ + * $Revision: 1.28 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -179,12 +179,12 @@ ccwgroup_create(struct device *root, || gdev->cdev[i]->id.driver_info != gdev->cdev[0]->id.driver_info) { rc = -EINVAL; - goto error; + goto free_dev; } /* Don't allow a device to belong to more than one group. */ if (gdev->cdev[i]->dev.driver_data) { rc = -EINVAL; - goto error; + goto free_dev; } } for (i = 0; i < argc; i++) @@ -207,8 +207,8 @@ ccwgroup_create(struct device *root, rc = device_register(&gdev->dev); if (rc) - goto error; - + goto free_dev; + get_device(&gdev->dev); rc = device_create_file(&gdev->dev, &dev_attr_ungroup); if (rc) { @@ -217,12 +217,21 @@ ccwgroup_create(struct device *root, } rc = __ccwgroup_create_symlinks(gdev); - if (!rc) + if (!rc) { + put_device(&gdev->dev); return 0; - + } device_remove_file(&gdev->dev, &dev_attr_ungroup); device_unregister(&gdev->dev); error: + for (i = 0; i < argc; i++) + if (gdev->cdev[i]) { + put_device(&gdev->cdev[i]->dev); + gdev->cdev[i]->dev.driver_data = NULL; + } + put_device(&gdev->dev); + return rc; +free_dev: for (i = 0; i < argc; i++) if (gdev->cdev[i]) { put_device(&gdev->cdev[i]->dev); @@ -230,7 +239,6 @@ error: gdev->cdev[i]->dev.driver_data = NULL; } kfree(gdev); - return rc; } diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 4a26cf1b1..4c8d6df06 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call - * $Revision: 1.110 $ + * $Revision: 1.112 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -24,7 +24,6 @@ #include "ioasm.h" #include "chsc.h" -#define CHPID_LONGS (256 / (8 * sizeof(long))) /* 256 chpids */ static struct channel_path *chps[NR_CHPIDS]; static void *sei_page; @@ -62,11 +61,11 @@ chpid_is_actually_online(int chp) int state; state = get_chp_status(chp); - if (state < 0) - new_channel_path(chp); - else + if (state < 0) { + need_rescan = 1; + queue_work(slow_path_wq, &slow_path_work); + } else WARN_ON(!state); - /* FIXME: should notify other subchannels here */ } /* FIXME: this is _always_ called for every subchannel. shouldn't we @@ -285,8 +284,10 @@ out_unlock: out_unreg: spin_unlock(&sch->lock); sch->lpm = 0; - /* We can't block here. */ - device_call_nopath_notify(sch); + if (css_enqueue_subchannel_slow(sch->irq)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } return 0; } @@ -303,6 +304,9 @@ s390_set_chpid_offline( __u8 chpid) bus_for_each_dev(&css_bus_type, NULL, &chpid, s390_subchannel_remove_chpid); + + if (need_rescan || css_slow_subchannels_exist()) + queue_work(slow_path_wq, &slow_path_work); } static int @@ -737,10 +741,12 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) * can successfully terminate, even using the * just varied off path. Then kill it. */ - if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) - /* Get over with it now. */ - device_call_nopath_notify(sch); - else if (sch->driver && sch->driver->verify) + if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) { + if (css_enqueue_subchannel_slow(sch->irq)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } + } else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); } break; @@ -773,11 +779,6 @@ s390_subchannel_vary_chpid_on(struct device *dev, void *data) return 0; } -extern void css_trigger_slow_path(void); -typedef void (*workfunc)(void *); -static DECLARE_WORK(varyonoff_work, (workfunc)css_trigger_slow_path, - NULL); - /* * Function: s390_vary_chpid * Varies the specified chpid online or offline @@ -813,7 +814,7 @@ s390_vary_chpid( __u8 chpid, int on) s390_subchannel_vary_chpid_on : s390_subchannel_vary_chpid_off); if (!on) - return 0; + goto out; /* Scan for new devices on varied on path. */ for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { struct schib schib; @@ -835,8 +836,9 @@ s390_vary_chpid( __u8 chpid, int on) need_rescan = 1; } } +out: if (need_rescan || css_slow_subchannels_exist()) - schedule_work(&varyonoff_work); + queue_work(slow_path_wq, &slow_path_work); return 0; } diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 6f02ac0c9..90f5a9e73 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -23,5 +23,4 @@ extern struct channel_path *chps[]; extern void s390_process_css( void ); extern void chsc_validate_chpids(struct subchannel *); extern void chpid_is_actually_online(int); -extern int is_chpid_online(int); #endif diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 3c786706b..a16f061fd 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.121 $ + * $Revision: 1.123 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -67,17 +67,17 @@ cio_debug_init (void) if (!cio_debug_msg_id) goto out_unregister; debug_register_view (cio_debug_msg_id, &debug_sprintf_view); - debug_set_level (cio_debug_msg_id, 6); + debug_set_level (cio_debug_msg_id, 2); cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8); if (!cio_debug_trace_id) goto out_unregister; debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); - debug_set_level (cio_debug_trace_id, 6); + debug_set_level (cio_debug_trace_id, 2); cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long)); if (!cio_debug_crw_id) goto out_unregister; debug_register_view (cio_debug_crw_id, &debug_sprintf_view); - debug_set_level (cio_debug_crw_id, 6); + debug_set_level (cio_debug_crw_id, 2); pr_debug("debugging initialized\n"); return 0; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 54beb1340..b834e6a72 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -136,7 +136,6 @@ void device_trigger_reprobe(struct subchannel *); /* Helper functions for vary on/off. */ void device_set_waiting(struct subchannel *); -void device_call_nopath_notify(struct subchannel *); /* Helper functions to build lists for the slow path. */ int css_enqueue_subchannel_slow(unsigned long schid); @@ -144,4 +143,7 @@ void css_walk_subchannel_slow_list(void (*fn)(unsigned long)); void css_clear_subchannel_slow_list(void); int css_slow_subchannels_exist(void); extern int need_rescan; + +extern struct workqueue_struct *slow_path_wq; +extern struct work_struct slow_path_work; #endif diff --git a/drivers/s390/cio/requestirq.c b/drivers/s390/cio/requestirq.c index acc5217be..0ce71a219 100644 --- a/drivers/s390/cio/requestirq.c +++ b/drivers/s390/cio/requestirq.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/requestirq.c * S/390 common I/O routines -- enabling and disabling of devices - * $Revision: 1.45 $ + * $Revision: 1.46 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -18,21 +18,6 @@ #include "css.h" -/* for compatiblity only... */ -int -request_irq (unsigned int irq, - void (*handler) (int, void *, struct pt_regs *), - unsigned long irqflags, const char *devname, void *dev_id) -{ - return -EINVAL; -} - -/* for compatiblity only... */ -void -free_irq (unsigned int irq, void *dev_id) -{ -} - struct pgid global_pgid; EXPORT_SYMBOL_GPL(global_pgid); diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h index 4ec1eaadf..dbc5dd0a5 100644 --- a/drivers/s390/crypto/z90crypt.h +++ b/drivers/s390/crypto/z90crypt.h @@ -46,12 +46,12 @@ * - length(n_modulus) = inputdatalength */ struct ica_rsa_modexpo { - char * inputdata; + char __user * inputdata; unsigned int inputdatalength; - char * outputdata; + char __user * outputdata; unsigned int outputdatalength; - char * b_key; - char * n_modulus; + char __user * b_key; + char __user * n_modulus; }; /** @@ -69,15 +69,15 @@ struct ica_rsa_modexpo { * - length(u_mult_inv) = inputdatalength/2 + 8 */ struct ica_rsa_modexpo_crt { - char * inputdata; + char __user * inputdata; unsigned int inputdatalength; - char * outputdata; + char __user * outputdata; unsigned int outputdatalength; - char * bp_key; - char * bq_key; - char * np_prime; - char * nq_prime; - char * u_mult_inv; + char __user * bp_key; + char __user * bq_key; + char __user * np_prime; + char __user * nq_prime; + char __user * u_mult_inv; }; #define Z90_IOCTL_MAGIC 'z' // NOTE: Need to allocate from linux folks diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 0190e2756..8ac1e9b75 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -361,7 +361,7 @@ struct work_element { int buff_size; // size of the buffer for the request char resp_buff[RESPBUFFSIZE]; int resp_buff_size; - char * resp_addr; // address of response in user space + char __user * resp_addr; // address of response in user space unsigned int funccode; // function code of request wait_queue_head_t waitq; unsigned long requestsent; // time at which the request was sent @@ -378,8 +378,9 @@ struct work_element { */ static int z90crypt_open(struct inode *, struct file *); static int z90crypt_release(struct inode *, struct file *); -static ssize_t z90crypt_read(struct file *, char *, size_t, loff_t *); -static ssize_t z90crypt_write(struct file *, const char *, size_t, loff_t *); +static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t z90crypt_write(struct file *, const char __user *, + size_t, loff_t *); static int z90crypt_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -389,7 +390,7 @@ static void z90crypt_config_task(unsigned long); static void z90crypt_cleanup_task(unsigned long); static int z90crypt_status(char *, char **, off_t, int, int *, void *); -static int z90crypt_status_write(struct file *, const char *, +static int z90crypt_status_write(struct file *, const char __user *, unsigned long, void *); /** @@ -473,9 +474,9 @@ static int trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) { - struct ica_rsa_modexpo_32 *mex32u = compat_ptr(arg); + struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg); struct ica_rsa_modexpo_32 mex32k; - struct ica_rsa_modexpo *mex64; + struct ica_rsa_modexpo __user *mex64; int ret = 0; unsigned int i; @@ -517,9 +518,9 @@ static int trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) { - struct ica_rsa_modexpo_crt_32 *crt32u = compat_ptr(arg); + struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg); struct ica_rsa_modexpo_crt_32 crt32k; - struct ica_rsa_modexpo_crt *crt64; + struct ica_rsa_modexpo_crt __user *crt64; int ret = 0; unsigned int i; @@ -841,7 +842,7 @@ z90crypt_release(struct inode *inode, struct file *filp) * z90crypt_read will not be supported beyond z90crypt 1.3.1 */ static ssize_t -z90crypt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { PDEBUG("filp %p (PID %d)\n", filp, PID()); return -EPERM; @@ -854,7 +855,7 @@ z90crypt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) */ #include static ssize_t -z90crypt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { unsigned char *temp_buff; @@ -892,7 +893,7 @@ z90crypt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) * Write is is not allowed */ static ssize_t -z90crypt_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +z90crypt_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { PDEBUG("filp %p (PID %d)\n", filp, PID()); return -EPERM; @@ -1258,7 +1259,7 @@ z90crypt_send(struct work_element *we_p, const char *buf) * process_results copies the user's work from kernel space. */ static inline int -z90crypt_process_results(struct work_element *we_p, char *buf) +z90crypt_process_results(struct work_element *we_p, char __user *buf) { int rv; @@ -1556,7 +1557,7 @@ get_crypto_request_buffer(struct work_element *we_p) static inline int z90crypt_prepare(struct work_element *we_p, unsigned int funccode, - const char *buffer) + const char __user *buffer) { int rv; @@ -1641,7 +1642,7 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid, PDEBUG("PID %d: allocate_work_element returned ENOMEM\n", pid); return rv; } - if ((rv = z90crypt_prepare(we_p, cmd, (const char *)arg))) + if ((rv = z90crypt_prepare(we_p, cmd, (const char __user *)arg))) PDEBUG("PID %d: rv = %d from z90crypt_prepare\n", pid, rv); if (!rv) if ((rv = z90crypt_send(we_p, (const char *)arg))) @@ -1653,7 +1654,7 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid, rv = we_p->retcode; } if (!rv) - rv = z90crypt_process_results(we_p, (char *)arg); + rv = z90crypt_process_results(we_p, (char __user *)arg); if ((we_p->status[0] & STAT_FAILED)) { switch (rv) { @@ -1748,49 +1749,49 @@ z90crypt_ioctl(struct inode *inode, struct file *filp, case Z90STAT_TOTALCOUNT: tempstat = get_status_totalcount(); - if (copy_to_user((int *)arg, &tempstat,sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat,sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_PCICACOUNT: tempstat = get_status_PCICAcount(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_PCICCCOUNT: tempstat = get_status_PCICCcount(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_PCIXCCCOUNT: tempstat = get_status_PCIXCCcount(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_REQUESTQ_COUNT: tempstat = get_status_requestq_count(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_PENDINGQ_COUNT: tempstat = get_status_pendingq_count(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_TOTALOPEN_COUNT: tempstat = get_status_totalopen_count(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; case Z90STAT_DOMAIN_INDEX: tempstat = get_status_domain_index(); - if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0) + if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0) ret = -EFAULT; break; @@ -1802,7 +1803,8 @@ z90crypt_ioctl(struct inode *inode, struct file *filp, break; } get_status_status_mask(status); - if (copy_to_user((char *) arg, status, Z90CRYPT_NUM_APS) != 0) + if (copy_to_user((char __user *) arg, status, Z90CRYPT_NUM_APS) + != 0) ret = -EFAULT; kfree(status); break; @@ -1815,7 +1817,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp, break; } get_status_qdepth_mask(qdepth); - if (copy_to_user((char *) arg, qdepth, Z90CRYPT_NUM_APS) != 0) + if (copy_to_user((char __user *) arg, qdepth, Z90CRYPT_NUM_APS) != 0) ret = -EFAULT; kfree(qdepth); break; @@ -1828,7 +1830,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp, break; } get_status_perdevice_reqcnt(reqcnt); - if (copy_to_user((char *) arg, reqcnt, + if (copy_to_user((char __user *) arg, reqcnt, Z90CRYPT_NUM_APS * sizeof(int)) != 0) ret = -EFAULT; kfree(reqcnt); @@ -1861,7 +1863,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp, get_status_status_mask(pstat->status); get_status_qdepth_mask(pstat->qdepth); - if (copy_to_user((struct ica_z90_status *) arg, pstat, + if (copy_to_user((struct ica_z90_status __user *) arg, pstat, sizeof(struct ica_z90_status)) != 0) ret = -EFAULT; kfree(pstat); @@ -2104,7 +2106,7 @@ scan_string(unsigned char *bf, unsigned int len, } static int -z90crypt_status_write(struct file *file, const char *buffer, +z90crypt_status_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { int i, j, len, offs, found, eof; @@ -2209,7 +2211,7 @@ z90crypt_status_write(struct file *file, const char *buffer, */ static inline int receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p, - unsigned char *buff, unsigned char **dest_p_p) + unsigned char *buff, unsigned char __user **dest_p_p) { int dv, rv; struct device *dev_ptr; @@ -2397,7 +2399,7 @@ helper_send_work(int index) static inline void helper_handle_work_element(int index, unsigned char psmid[8], int rc, int buff_len, unsigned char *buff, - unsigned char *resp_addr) + unsigned char __user *resp_addr) { struct work_element *pq_p; struct list_head *lptr, *tptr; @@ -2502,7 +2504,8 @@ static void z90crypt_reader_task(unsigned long ptr) { int workavail, remaining, index, rc, buff_len; - unsigned char psmid[8], *resp_addr; + unsigned char psmid[8]; + unsigned char __user *resp_addr; static unsigned char buff[1024]; PDEBUG("jiffies %ld\n", jiffies); diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c index 1120f79cb..3755f9947 100644 --- a/drivers/s390/net/ctctty.c +++ b/drivers/s390/net/ctctty.c @@ -515,7 +515,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou } skb_reserve(skb, skb_res); if (from_user) - copy_from_user(skb_put(skb, c), buf, c); + copy_from_user(skb_put(skb, c), + (const u_char __user *)buf, c); else memcpy(skb_put(skb, c), buf, c); skb_queue_tail(&info->tx_queue, skb); @@ -640,7 +641,7 @@ ctc_tty_unthrottle(struct tty_struct *tty) * allows RS485 driver to be written in user space. */ static int -ctc_tty_get_lsr_info(ctc_tty_info * info, uint * value) +ctc_tty_get_lsr_info(ctc_tty_info * info, uint __user *value) { u_char status; uint result; @@ -650,7 +651,7 @@ ctc_tty_get_lsr_info(ctc_tty_info * info, uint * value) status = info->lsr; spin_unlock_irqrestore(&ctc_tty_lock, flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - put_user(result, (uint *) value); + put_user(result, value); return 0; } @@ -743,14 +744,14 @@ ctc_tty_ioctl(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME, info->line); #endif - error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); + error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg); return error; case TIOCSSOFTCAR: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME, info->line); #endif - error = get_user(arg, (ulong *) arg); + error = get_user(arg, (ulong __user *) arg); if (error) return error; tty->termios->c_cflag = @@ -762,11 +763,11 @@ ctc_tty_ioctl(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME, info->line); #endif - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + error = verify_area(VERIFY_WRITE, (void __user *) arg, sizeof(uint)); if (error) return error; else - return ctc_tty_get_lsr_info(info, (uint *) arg); + return ctc_tty_get_lsr_info(info, (uint __user *) arg); default: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd, diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 2138af884..ffa996c8a 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -21,13 +22,14 @@ // #define DBG(args,...) do {} while (0); static struct semaphore m_sem; -static struct semaphore s_sem; extern int css_process_crw(int); extern int chsc_process_crw(void); extern int chp_process_crw(int, int); extern void css_reiterate_subchannels(void); -extern void css_trigger_slow_path(void); + +extern struct workqueue_struct *slow_path_wq; +extern struct work_struct slow_path_work; static void s390_handle_damage(char *msg) @@ -39,21 +41,6 @@ s390_handle_damage(char *msg) disabled_wait((unsigned long) __builtin_return_address(0)); } -static int -s390_mchk_slow_path(void *param) -{ - struct semaphore *sem; - - sem = (struct semaphore *)param; - /* Set a nice name. */ - daemonize("kslowcrw"); -repeat: - down_interruptible(sem); - css_trigger_slow_path(); - goto repeat; - return 0; -} - /* * Retrieve CRWs and call function to handle event. * @@ -130,7 +117,7 @@ repeat: } } if (slow) - up(&s_sem); + queue_work(slow_path_wq, &slow_path_work); goto repeat; return 0; } @@ -202,7 +189,6 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - init_MUTEX_LOCKED( &s_sem ); ctl_clear_bit(14, 25); /* disable damage MCH */ ctl_set_bit(14, 26); /* enable degradation MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */ @@ -226,7 +212,6 @@ static int __init machine_check_crw_init (void) { kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES); - kernel_thread(s390_mchk_slow_path, &s_sem, CLONE_FS|CLONE_FILES); ctl_set_bit(14, 28); /* enable channel report MCH */ return 0; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c new file mode 100644 index 000000000..e9c5098ed --- /dev/null +++ b/drivers/scsi/ipr.c @@ -0,0 +1,6021 @@ +/* + * ipr.c -- driver for IBM Power Linux RAID adapters + * + * Written By: Brian King, IBM Corporation + * + * Copyright (C) 2003, 2004 IBM 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) 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 + * + */ + +/* + * Notes: + * + * This driver is used to control the following SCSI adapters: + * + * IBM iSeries: 5702, 5703, 2780, 5709, 570A, 570B + * + * IBM pSeries: PCI-X Dual Channel Ultra 320 SCSI RAID Adapter + * PCI-X Dual Channel Ultra 320 SCSI Adapter + * PCI-X Dual Channel Ultra 320 SCSI RAID Enablement Card + * Embedded SCSI adapter on p615 and p655 systems + * + * Supported Hardware Features: + * - Ultra 320 SCSI controller + * - PCI-X host interface + * - Embedded PowerPC RISC Processor and Hardware XOR DMA Engine + * - Non-Volatile Write Cache + * - Supports attachment of non-RAID disks, tape, and optical devices + * - RAID Levels 0, 5, 10 + * - Hot spare + * - Background Parity Checking + * - Background Data Scrubbing + * - Ability to increase the capacity of an existing RAID 5 disk array + * by adding disks + * + * Driver Features: + * - Tagged command queuing + * - Adapter microcode download + * - PCI hot plug + * - SCSI device hot plug + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipr.h" + +/* + * Global Data + */ +static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head); +static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; +static unsigned int ipr_max_speed = 1; +static int ipr_testmode = 0; +static spinlock_t ipr_driver_lock = SPIN_LOCK_UNLOCKED; + +/* This table describes the differences between DMA controller chips */ +static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { + { /* Gemstone */ + .mailbox = 0x0042C, + .cache_line_size = 0x20, + { + .set_interrupt_mask_reg = 0x0022C, + .clr_interrupt_mask_reg = 0x00230, + .sense_interrupt_mask_reg = 0x0022C, + .clr_interrupt_reg = 0x00228, + .sense_interrupt_reg = 0x00224, + .ioarrin_reg = 0x00404, + .sense_uproc_interrupt_reg = 0x00214, + .set_uproc_interrupt_reg = 0x00214, + .clr_uproc_interrupt_reg = 0x00218 + } + }, + { /* Snipe */ + .mailbox = 0x0052C, + .cache_line_size = 0x20, + { + .set_interrupt_mask_reg = 0x00288, + .clr_interrupt_mask_reg = 0x0028C, + .sense_interrupt_mask_reg = 0x00288, + .clr_interrupt_reg = 0x00284, + .sense_interrupt_reg = 0x00280, + .ioarrin_reg = 0x00504, + .sense_uproc_interrupt_reg = 0x00290, + .set_uproc_interrupt_reg = 0x00290, + .clr_uproc_interrupt_reg = 0x00294 + } + }, +}; + +static int ipr_max_bus_speeds [] = { + IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE +}; + +MODULE_AUTHOR("Brian King "); +MODULE_DESCRIPTION("IBM Power RAID SCSI Adapter Driver"); +module_param_named(max_speed, ipr_max_speed, uint, 0); +MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320"); +module_param_named(log_level, ipr_log_level, uint, 0); +MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); +module_param_named(testmode, ipr_testmode, int, 0); +MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(IPR_DRIVER_VERSION); + +static const char *ipr_gpdd_dev_end_states[] = { + "Command complete", + "Terminated by host", + "Terminated by device reset", + "Terminated by bus reset", + "Unknown", + "Command not started" +}; + +static const char *ipr_gpdd_dev_bus_phases[] = { + "Bus free", + "Arbitration", + "Selection", + "Message out", + "Command", + "Message in", + "Data out", + "Data in", + "Status", + "Reselection", + "Unknown" +}; + +/* A constant array of IOASCs/URCs/Error Messages */ +static const +struct ipr_error_table_t ipr_error_table[] = { + {0x00000000, 1, 1, + "8155: An unknown error was received"}, + {0x00330000, 0, 0, + "Soft underlength error"}, + {0x005A0000, 0, 0, + "Command to be cancelled not found"}, + {0x00808000, 0, 0, + "Qualified success"}, + {0x01080000, 1, 1, + "FFFE: Soft device bus error recovered by the IOA"}, + {0x01170600, 0, 1, + "FFF9: Device sector reassign successful"}, + {0x01170900, 0, 1, + "FFF7: Media error recovered by device rewrite procedures"}, + {0x01180200, 0, 1, + "7001: IOA sector reassignment successful"}, + {0x01180500, 0, 1, + "FFF9: Soft media error. Sector reassignment recommended"}, + {0x01180600, 0, 1, + "FFF7: Media error recovered by IOA rewrite procedures"}, + {0x01418000, 0, 1, + "FF3D: Soft PCI bus error recovered by the IOA"}, + {0x01440000, 1, 1, + "FFF6: Device hardware error recovered by the IOA"}, + {0x01448100, 0, 1, + "FFF6: Device hardware error recovered by the device"}, + {0x01448200, 1, 1, + "FF3D: Soft IOA error recovered by the IOA"}, + {0x01448300, 0, 1, + "FFFA: Undefined device response recovered by the IOA"}, + {0x014A0000, 1, 1, + "FFF6: Device bus error, message or command phase"}, + {0x015D0000, 0, 1, + "FFF6: Failure prediction threshold exceeded"}, + {0x015D9200, 0, 1, + "8009: Impending cache battery pack failure"}, + {0x02040400, 0, 0, + "34FF: Disk device format in progress"}, + {0x023F0000, 0, 0, + "Synchronization required"}, + {0x024E0000, 0, 0, + "No ready, IOA shutdown"}, + {0x02670100, 0, 1, + "3020: Storage subsystem configuration error"}, + {0x03110B00, 0, 0, + "FFF5: Medium error, data unreadable, recommend reassign"}, + {0x03110C00, 0, 0, + "7000: Medium error, data unreadable, do not reassign"}, + {0x03310000, 0, 1, + "FFF3: Disk media format bad"}, + {0x04050000, 0, 1, + "3002: Addressed device failed to respond to selection"}, + {0x04080000, 1, 1, + "3100: Device bus error"}, + {0x04080100, 0, 1, + "3109: IOA timed out a device command"}, + {0x04088000, 0, 0, + "3120: SCSI bus is not operational"}, + {0x04118000, 0, 1, + "9000: IOA reserved area data check"}, + {0x04118100, 0, 1, + "9001: IOA reserved area invalid data pattern"}, + {0x04118200, 0, 1, + "9002: IOA reserved area LRC error"}, + {0x04320000, 0, 1, + "102E: Out of alternate sectors for disk storage"}, + {0x04330000, 1, 1, + "FFF4: Data transfer underlength error"}, + {0x04338000, 1, 1, + "FFF4: Data transfer overlength error"}, + {0x043E0100, 0, 1, + "3400: Logical unit failure"}, + {0x04408500, 0, 1, + "FFF4: Device microcode is corrupt"}, + {0x04418000, 1, 1, + "8150: PCI bus error"}, + {0x04430000, 1, 0, + "Unsupported device bus message received"}, + {0x04440000, 1, 1, + "FFF4: Disk device problem"}, + {0x04448200, 1, 1, + "8150: Permanent IOA failure"}, + {0x04448300, 0, 1, + "3010: Disk device returned wrong response to IOA"}, + {0x04448400, 0, 1, + "8151: IOA microcode error"}, + {0x04448500, 0, 0, + "Device bus status error"}, + {0x04448600, 0, 1, + "8157: IOA error requiring IOA reset to recover"}, + {0x04490000, 0, 0, + "Message reject received from the device"}, + {0x04449200, 0, 1, + "8008: A permanent cache battery pack failure occurred"}, + {0x0444A000, 0, 1, + "9090: Disk unit has been modified after the last known status"}, + {0x0444A200, 0, 1, + "9081: IOA detected device error"}, + {0x0444A300, 0, 1, + "9082: IOA detected device error"}, + {0x044A0000, 1, 1, + "3110: Device bus error, message or command phase"}, + {0x04670400, 0, 1, + "9091: Incorrect hardware configuration change has been detected"}, + {0x046E0000, 0, 1, + "FFF4: Command to logical unit failed"}, + {0x05240000, 1, 0, + "Illegal request, invalid request type or request packet"}, + {0x05250000, 0, 0, + "Illegal request, invalid resource handle"}, + {0x05260000, 0, 0, + "Illegal request, invalid field in parameter list"}, + {0x05260100, 0, 0, + "Illegal request, parameter not supported"}, + {0x05260200, 0, 0, + "Illegal request, parameter value invalid"}, + {0x052C0000, 0, 0, + "Illegal request, command sequence error"}, + {0x06040500, 0, 1, + "9031: Array protection temporarily suspended, protection resuming"}, + {0x06040600, 0, 1, + "9040: Array protection temporarily suspended, protection resuming"}, + {0x06290000, 0, 1, + "FFFB: SCSI bus was reset"}, + {0x06290500, 0, 0, + "FFFE: SCSI bus transition to single ended"}, + {0x06290600, 0, 0, + "FFFE: SCSI bus transition to LVD"}, + {0x06298000, 0, 1, + "FFFB: SCSI bus was reset by another initiator"}, + {0x063F0300, 0, 1, + "3029: A device replacement has occurred"}, + {0x064C8000, 0, 1, + "9051: IOA cache data exists for a missing or failed device"}, + {0x06670100, 0, 1, + "9025: Disk unit is not supported at its physical location"}, + {0x06670600, 0, 1, + "3020: IOA detected a SCSI bus configuration error"}, + {0x06678000, 0, 1, + "3150: SCSI bus configuration error"}, + {0x06690200, 0, 1, + "9041: Array protection temporarily suspended"}, + {0x066B0200, 0, 1, + "9030: Array no longer protected due to missing or failed disk unit"}, + {0x07270000, 0, 0, + "Failure due to other device"}, + {0x07278000, 0, 1, + "9008: IOA does not support functions expected by devices"}, + {0x07278100, 0, 1, + "9010: Cache data associated with attached devices cannot be found"}, + {0x07278200, 0, 1, + "9011: Cache data belongs to devices other than those attached"}, + {0x07278400, 0, 1, + "9020: Array missing 2 or more devices with only 1 device present"}, + {0x07278500, 0, 1, + "9021: Array missing 2 or more devices with 2 or more devices present"}, + {0x07278600, 0, 1, + "9022: Exposed array is missing a required device"}, + {0x07278700, 0, 1, + "9023: Array member(s) not at required physical locations"}, + {0x07278800, 0, 1, + "9024: Array not functional due to present hardware configuration"}, + {0x07278900, 0, 1, + "9026: Array not functional due to present hardware configuration"}, + {0x07278A00, 0, 1, + "9027: Array is missing a device and parity is out of sync"}, + {0x07278B00, 0, 1, + "9028: Maximum number of arrays already exist"}, + {0x07278C00, 0, 1, + "9050: Required cache data cannot be located for a disk unit"}, + {0x07278D00, 0, 1, + "9052: Cache data exists for a device that has been modified"}, + {0x07278F00, 0, 1, + "9054: IOA resources not available due to previous problems"}, + {0x07279100, 0, 1, + "9092: Disk unit requires initialization before use"}, + {0x07279200, 0, 1, + "9029: Incorrect hardware configuration change has been detected"}, + {0x07279600, 0, 1, + "9060: One or more disk pairs are missing from an array"}, + {0x07279700, 0, 1, + "9061: One or more disks are missing from an array"}, + {0x07279800, 0, 1, + "9062: One or more disks are missing from an array"}, + {0x07279900, 0, 1, + "9063: Maximum number of functional arrays has been exceeded"}, + {0x0B260000, 0, 0, + "Aborted command, invalid descriptor"}, + {0x0B5A0000, 0, 0, + "Command terminated by host"} +}; + +static const struct ipr_ses_table_entry ipr_ses_table[] = { + { "2104-DL1 ", "XXXXXXXXXXXXXXXX", 80 }, + { "2104-TL1 ", "XXXXXXXXXXXXXXXX", 80 }, + { "HSBP07M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 7 slot */ + { "HSBP05M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 5 slot */ + { "HSBP05M S U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Bowtie */ + { "HSBP06E ASU2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* MartinFenning */ + { "2104-DU3 ", "XXXXXXXXXXXXXXXX", 160 }, + { "2104-TU3 ", "XXXXXXXXXXXXXXXX", 160 }, + { "HSBP04C RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, + { "HSBP06E RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, + { "St V1S2 ", "XXXXXXXXXXXXXXXX", 160 }, + { "HSBPD4M PU3SCSI", "XXXXXXX*XXXXXXXX", 160 }, + { "VSBPD1H U3SCSI", "XXXXXXX*XXXXXXXX", 160 } +}; + +/* + * Function Prototypes + */ +static int ipr_reset_alert(struct ipr_cmnd *); +static void ipr_process_ccn(struct ipr_cmnd *); +static void ipr_process_error(struct ipr_cmnd *); +static void ipr_reset_ioa_job(struct ipr_cmnd *); +static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *, + enum ipr_shutdown_type); + +#ifdef CONFIG_SCSI_IPR_TRACE +/** + * ipr_trc_hook - Add a trace entry to the driver trace + * @ipr_cmd: ipr command struct + * @type: trace type + * @add_data: additional data + * + * Return value: + * none + **/ +static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, + u8 type, u32 add_data) +{ + struct ipr_trace_entry *trace_entry; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++]; + trace_entry->time = jiffies; + trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; + trace_entry->type = type; + trace_entry->cmd_index = ipr_cmd->cmd_index; + trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; + trace_entry->u.add_data = add_data; +} +#else +#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0) +#endif + +/** + * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse + * @ipr_cmd: ipr command struct + * + * Return value: + * none + **/ +static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + + memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); + ioarcb->write_data_transfer_length = 0; + ioarcb->read_data_transfer_length = 0; + ioarcb->write_ioadl_len = 0; + ioarcb->read_ioadl_len = 0; + ioasa->ioasc = 0; + ioasa->residual_data_len = 0; + + ipr_cmd->scsi_cmd = NULL; + ipr_cmd->sense_buffer[0] = 0; + ipr_cmd->dma_use_sg = 0; +} + +/** + * ipr_init_ipr_cmnd - Initialize an IPR Cmnd block + * @ipr_cmd: ipr command struct + * + * Return value: + * none + **/ +static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd) +{ + ipr_reinit_ipr_cmnd(ipr_cmd); + ipr_cmd->u.scratch = 0; + init_timer(&ipr_cmd->timer); +} + +/** + * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block + * @ioa_cfg: ioa config struct + * + * Return value: + * pointer to ipr command struct + **/ +static +struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg) +{ + struct ipr_cmnd *ipr_cmd; + + ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue); + list_del(&ipr_cmd->queue); + ipr_init_ipr_cmnd(ipr_cmd); + + return ipr_cmd; +} + +/** + * ipr_unmap_sglist - Unmap scatterlist if mapped + * @ioa_cfg: ioa config struct + * @ipr_cmd: ipr command struct + * + * Return value: + * nothing + **/ +static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_cmnd *ipr_cmd) +{ + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + + if (ipr_cmd->dma_use_sg) { + if (scsi_cmd->use_sg > 0) { + pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer, + scsi_cmd->use_sg, + scsi_cmd->sc_data_direction); + } else { + pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle, + scsi_cmd->request_bufflen, + scsi_cmd->sc_data_direction); + } + } +} + +/** + * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts + * @ioa_cfg: ioa config struct + * @clr_ints: interrupts to clear + * + * This function masks all interrupts on the adapter, then clears the + * interrupts specified in the mask + * + * Return value: + * none + **/ +static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg, + u32 clr_ints) +{ + volatile u32 int_reg; + + /* Stop new interrupts */ + ioa_cfg->allow_interrupts = 0; + + /* Set interrupt mask to stop all new interrupts */ + writel(~0, ioa_cfg->regs.set_interrupt_mask_reg); + + /* Clear any pending interrupts */ + writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); +} + +/** + * ipr_save_pcix_cmd_reg - Save PCI-X command register + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / -EIO on failure + **/ +static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) +{ + int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); + + if (pcix_cmd_reg == 0) { + dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); + return -EIO; + } + + if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg, + &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { + dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); + return -EIO; + } + + ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO; + return 0; +} + +/** + * ipr_set_pcix_cmd_reg - Setup PCI-X command register + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / -EIO on failure + **/ +static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) +{ + int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); + + if (pcix_cmd_reg) { + if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg, + ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { + dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); + return -EIO; + } + } else { + dev_err(&ioa_cfg->pdev->dev, + "Failed to setup PCI-X command register\n"); + return -EIO; + } + + return 0; +} + +/** + * ipr_scsi_eh_done - mid-layer done function for aborted ops + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler for + * ops generated by the SCSI mid-layer which are being aborted. + * + * Return value: + * none + **/ +static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + + scsi_cmd->result |= (DID_ERROR << 16); + + ipr_unmap_sglist(ioa_cfg, ipr_cmd); + scsi_cmd->scsi_done(scsi_cmd); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); +} + +/** + * ipr_fail_all_ops - Fails all outstanding ops. + * @ioa_cfg: ioa config struct + * + * This function fails all outstanding ops. + * + * Return value: + * none + **/ +static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) +{ + struct ipr_cmnd *ipr_cmd, *temp; + + ENTER; + list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) { + list_del(&ipr_cmd->queue); + + ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET); + ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID); + + if (ipr_cmd->scsi_cmd) + ipr_cmd->done = ipr_scsi_eh_done; + + ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); + del_timer(&ipr_cmd->timer); + ipr_cmd->done(ipr_cmd); + } + + LEAVE; +} + +/** + * ipr_do_req - Send driver initiated requests. + * @ipr_cmd: ipr command struct + * @done: done function + * @timeout_func: timeout function + * @timeout: timeout value + * + * This function sends the specified command to the adapter with the + * timeout given. The done function is invoked on command completion. + * + * Return value: + * none + **/ +static void ipr_do_req(struct ipr_cmnd *ipr_cmd, + void (*done) (struct ipr_cmnd *), + void (*timeout_func) (struct ipr_cmnd *), u32 timeout) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + + ipr_cmd->done = done; + + ipr_cmd->timer.data = (unsigned long) ipr_cmd; + ipr_cmd->timer.expires = jiffies + timeout; + ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func; + + add_timer(&ipr_cmd->timer); + + ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0); + + mb(); + writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), + ioa_cfg->regs.ioarrin_reg); +} + +/** + * ipr_internal_cmd_done - Op done function for an internally generated op. + * @ipr_cmd: ipr command struct + * + * This function is the op done function for an internally generated, + * blocking op. It simply wakes the sleeping thread. + * + * Return value: + * none + **/ +static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd) +{ + if (ipr_cmd->u.sibling) + ipr_cmd->u.sibling = NULL; + else + complete(&ipr_cmd->completion); +} + +/** + * ipr_send_blocking_cmd - Send command and sleep on its completion. + * @ipr_cmd: ipr command struct + * @timeout_func: function to invoke if command times out + * @timeout: timeout + * + * Return value: + * none + **/ +static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, + void (*timeout_func) (struct ipr_cmnd *ipr_cmd), + u32 timeout) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + init_completion(&ipr_cmd->completion); + ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout); + + spin_unlock_irq(ioa_cfg->host->host_lock); + wait_for_completion(&ipr_cmd->completion); + spin_lock_irq(ioa_cfg->host->host_lock); +} + +/** + * ipr_send_hcam - Send an HCAM to the adapter. + * @ioa_cfg: ioa config struct + * @type: HCAM type + * @hostrcb: hostrcb struct + * + * This function will send a Host Controlled Async command to the adapter. + * If HCAMs are currently not allowed to be issued to the adapter, it will + * place the hostrcb on the free queue. + * + * Return value: + * none + **/ +static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + + if (ioa_cfg->allow_cmds) { + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q); + + ipr_cmd->u.hostrcb = hostrcb; + ioarcb = &ipr_cmd->ioarcb; + + ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM; + ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC; + ioarcb->cmd_pkt.cdb[1] = type; + ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff; + ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff; + + ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam)); + ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ipr_cmd->ioadl[0].flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam)); + ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma); + + if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE) + ipr_cmd->done = ipr_process_ccn; + else + ipr_cmd->done = ipr_process_error; + + ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR); + + mb(); + writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), + ioa_cfg->regs.ioarrin_reg); + } else { + list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); + } +} + +/** + * ipr_init_res_entry - Initialize a resource entry struct. + * @res: resource entry struct + * + * Return value: + * none + **/ +static void ipr_init_res_entry(struct ipr_resource_entry *res) +{ + res->needs_sync_complete = 1; + res->in_erp = 0; + res->add_to_ml = 0; + res->del_from_ml = 0; + res->resetting_device = 0; + res->tcq_active = 0; + res->qdepth = IPR_MAX_CMD_PER_LUN; + res->sdev = NULL; +} + +/** + * ipr_handle_config_change - Handle a config change from the adapter + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb + * + * Return value: + * none + **/ +static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_resource_entry *res = NULL; + struct ipr_config_table_entry *cfgte; + u32 is_ndn = 1; + + cfgte = &hostrcb->hcam.u.ccn.cfgte; + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr, + sizeof(cfgte->res_addr))) { + is_ndn = 0; + break; + } + } + + if (is_ndn) { + if (list_empty(&ioa_cfg->free_res_q)) { + ipr_send_hcam(ioa_cfg, + IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, + hostrcb); + return; + } + + res = list_entry(ioa_cfg->free_res_q.next, + struct ipr_resource_entry, queue); + + list_del(&res->queue); + ipr_init_res_entry(res); + list_add_tail(&res->queue, &ioa_cfg->used_res_q); + } + + memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry)); + + if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { + if (res->sdev) { + res->sdev->hostdata = NULL; + res->del_from_ml = 1; + if (ioa_cfg->allow_ml_add_del) + schedule_work(&ioa_cfg->work_q); + } else + list_move_tail(&res->queue, &ioa_cfg->free_res_q); + } else if (!res->sdev) { + res->add_to_ml = 1; + if (ioa_cfg->allow_ml_add_del) + schedule_work(&ioa_cfg->work_q); + } + + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); +} + +/** + * ipr_process_ccn - Op done function for a CCN. + * @ipr_cmd: ipr command struct + * + * This function is the op done function for a configuration + * change notification host controlled async from the adapter. + * + * Return value: + * none + **/ +static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + list_del(&hostrcb->queue); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + + if (ioasc) { + if (ioasc != IPR_IOASC_IOA_WAS_RESET) + dev_err(&ioa_cfg->pdev->dev, + "Host RCB failed with IOASC: 0x%08X\n", ioasc); + + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); + } else { + ipr_handle_config_change(ioa_cfg, hostrcb); + } +} + +/** + * ipr_log_vpd - Log the passed VPD to the error log. + * @vpids: vendor/product id struct + * @serial_num: serial number string + * + * Return value: + * none + **/ +static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num) +{ + char buffer[max_t(int, sizeof(struct ipr_std_inq_vpids), + IPR_SERIAL_NUM_LEN) + 1]; + + memcpy(buffer, vpids, sizeof(struct ipr_std_inq_vpids)); + buffer[sizeof(struct ipr_std_inq_vpids)] = '\0'; + ipr_err("Vendor/Product ID: %s\n", buffer); + + memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN); + buffer[IPR_SERIAL_NUM_LEN] = '\0'; + ipr_err(" Serial Number: %s\n", buffer); +} + +/** + * ipr_log_cache_error - Log a cache error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_02_error *error = + &hostrcb->hcam.u.error.u.type_02_error; + + ipr_err("-----Current Configuration-----\n"); + ipr_err("Cache Directory Card Information:\n"); + ipr_log_vpd(&error->ioa_vpids, error->ioa_sn); + ipr_err("Adapter Card Information:\n"); + ipr_log_vpd(&error->cfc_vpids, error->cfc_sn); + + ipr_err("-----Expected Configuration-----\n"); + ipr_err("Cache Directory Card Information:\n"); + ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpids, + error->ioa_last_attached_to_cfc_sn); + ipr_err("Adapter Card Information:\n"); + ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpids, + error->cfc_last_attached_to_ioa_sn); + + ipr_err("Additional IOA Data: %08X %08X %08X\n", + be32_to_cpu(error->ioa_data[0]), + be32_to_cpu(error->ioa_data[1]), + be32_to_cpu(error->ioa_data[2])); +} + +/** + * ipr_log_config_error - Log a configuration error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + int errors_logged, i; + struct ipr_hostrcb_device_data_entry *dev_entry; + struct ipr_hostrcb_type_03_error *error; + + error = &hostrcb->hcam.u.error.u.type_03_error; + errors_logged = be32_to_cpu(error->errors_logged); + + ipr_err("Device Errors Detected/Logged: %d/%d\n", + be32_to_cpu(error->errors_detected), errors_logged); + + dev_entry = error->dev_entry; + + for (i = 0; i < errors_logged; i++, dev_entry++) { + ipr_err_separator; + + if (dev_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { + ipr_err("Device %d: missing\n", i + 1); + } else { + ipr_err("Device %d: %d:%d:%d:%d\n", i + 1, + ioa_cfg->host->host_no, dev_entry->dev_res_addr.bus, + dev_entry->dev_res_addr.target, dev_entry->dev_res_addr.lun); + } + ipr_log_vpd(&dev_entry->dev_vpids, dev_entry->dev_sn); + + ipr_err("-----New Device Information-----\n"); + ipr_log_vpd(&dev_entry->new_dev_vpids, dev_entry->new_dev_sn); + + ipr_err("Cache Directory Card Information:\n"); + ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpids, + dev_entry->ioa_last_with_dev_sn); + + ipr_err("Adapter Card Information:\n"); + ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpids, + dev_entry->cfc_last_with_dev_sn); + + ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n", + be32_to_cpu(dev_entry->ioa_data[0]), + be32_to_cpu(dev_entry->ioa_data[1]), + be32_to_cpu(dev_entry->ioa_data[2]), + be32_to_cpu(dev_entry->ioa_data[3]), + be32_to_cpu(dev_entry->ioa_data[4])); + } +} + +/** + * ipr_log_array_error - Log an array configuration error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + int i; + struct ipr_hostrcb_type_04_error *error; + struct ipr_hostrcb_array_data_entry *array_entry; + u8 zero_sn[IPR_SERIAL_NUM_LEN]; + + memset(zero_sn, '0', IPR_SERIAL_NUM_LEN); + + error = &hostrcb->hcam.u.error.u.type_04_error; + + ipr_err_separator; + + ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", + error->protection_level, + ioa_cfg->host->host_no, + error->last_func_vset_res_addr.bus, + error->last_func_vset_res_addr.target, + error->last_func_vset_res_addr.lun); + + ipr_err_separator; + + array_entry = error->array_member; + + for (i = 0; i < 18; i++) { + if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN)) + continue; + + if (error->exposed_mode_adn == i) { + ipr_err("Exposed Array Member %d:\n", i); + } else { + ipr_err("Array Member %d:\n", i); + } + + ipr_log_vpd(&array_entry->vpids, array_entry->serial_num); + + if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { + ipr_err("Current Location: unknown\n"); + } else { + ipr_err("Current Location: %d:%d:%d:%d\n", + ioa_cfg->host->host_no, + array_entry->dev_res_addr.bus, + array_entry->dev_res_addr.target, + array_entry->dev_res_addr.lun); + } + + if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { + ipr_err("Expected Location: unknown\n"); + } else { + ipr_err("Expected Location: %d:%d:%d:%d\n", + ioa_cfg->host->host_no, + array_entry->expected_dev_res_addr.bus, + array_entry->expected_dev_res_addr.target, + array_entry->expected_dev_res_addr.lun); + } + + ipr_err_separator; + + if (i == 9) + array_entry = error->array_member2; + else + array_entry++; + } +} + +/** + * ipr_log_generic_error - Log an adapter error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + int i; + int ioa_data_len = be32_to_cpu(hostrcb->hcam.length); + + if (ioa_data_len == 0) + return; + + ipr_err("IOA Error Data:\n"); + ipr_err("Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + + for (i = 0; i < ioa_data_len / 4; i += 4) { + ipr_err("%08X: %08X %08X %08X %08X\n", i*4, + be32_to_cpu(hostrcb->hcam.u.raw.data[i]), + be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]), + be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]), + be32_to_cpu(hostrcb->hcam.u.raw.data[i+3])); + } +} + +/** + * ipr_get_error - Find the specfied IOASC in the ipr_error_table. + * @ioasc: IOASC + * + * This function will return the index of into the ipr_error_table + * for the specified IOASC. If the IOASC is not in the table, + * 0 will be returned, which points to the entry used for unknown errors. + * + * Return value: + * index into the ipr_error_table + **/ +static u32 ipr_get_error(u32 ioasc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++) + if (ipr_error_table[i].ioasc == ioasc) + return i; + + return 0; +} + +/** + * ipr_handle_log_data - Log an adapter error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * This function logs an adapter error to the system. + * + * Return value: + * none + **/ +static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + u32 ioasc; + int error_index; + + if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY) + return; + + if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST) + dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n"); + + ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); + + if (ioasc == IPR_IOASC_BUS_WAS_RESET || + ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) { + /* Tell the midlayer we had a bus reset so it will handle the UA properly */ + scsi_report_bus_reset(ioa_cfg->host, + hostrcb->hcam.u.error.failing_dev_res_addr.bus); + } + + error_index = ipr_get_error(ioasc); + + if (!ipr_error_table[error_index].log_hcam) + return; + + if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { + ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, + "%s\n", ipr_error_table[error_index].error); + } else { + dev_err(&ioa_cfg->pdev->dev, "%s\n", + ipr_error_table[error_index].error); + } + + /* Set indication we have logged an error */ + ioa_cfg->errors_logged++; + + if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) + return; + + switch (hostrcb->hcam.overlay_id) { + case IPR_HOST_RCB_OVERLAY_ID_1: + ipr_log_generic_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_2: + ipr_log_cache_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_3: + ipr_log_config_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_4: + case IPR_HOST_RCB_OVERLAY_ID_6: + ipr_log_array_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: + ipr_log_generic_error(ioa_cfg, hostrcb); + break; + default: + dev_err(&ioa_cfg->pdev->dev, + "Unknown error received. Overlay ID: %d\n", + hostrcb->hcam.overlay_id); + break; + } +} + +/** + * ipr_process_error - Op done function for an adapter error log. + * @ipr_cmd: ipr command struct + * + * This function is the op done function for an error log host + * controlled async from the adapter. It will log the error and + * send the HCAM back to the adapter. + * + * Return value: + * none + **/ +static void ipr_process_error(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + list_del(&hostrcb->queue); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + + if (!ioasc) { + ipr_handle_log_data(ioa_cfg, hostrcb); + } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) { + dev_err(&ioa_cfg->pdev->dev, + "Host RCB failed with IOASC: 0x%08X\n", ioasc); + } + + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); +} + +/** + * ipr_timeout - An internally generated op has timed out. + * @ipr_cmd: ipr command struct + * + * This function blocks host requests and initiates an + * adapter reset. + * + * Return value: + * none + **/ +static void ipr_timeout(struct ipr_cmnd *ipr_cmd) +{ + unsigned long lock_flags = 0; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + ioa_cfg->errors_logged++; + dev_err(&ioa_cfg->pdev->dev, + "Adapter being reset due to command timeout.\n"); + + if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) + ioa_cfg->sdt_state = GET_DUMP; + + if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + LEAVE; +} + +/** + * ipr_reset_reload - Reset/Reload the IOA + * @ioa_cfg: ioa config struct + * @shutdown_type: shutdown type + * + * This function resets the adapter and re-initializes it. + * This function assumes that all new host commands have been stopped. + * Return value: + * SUCCESS / FAILED + **/ +static int ipr_reset_reload(struct ipr_ioa_cfg *ioa_cfg, + enum ipr_shutdown_type shutdown_type) +{ + if (!ioa_cfg->in_reset_reload) + ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); + + spin_unlock_irq(ioa_cfg->host->host_lock); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irq(ioa_cfg->host->host_lock); + + /* If we got hit with a host reset while we were already resetting + the adapter for some reason, and the reset failed. */ + if (ioa_cfg->ioa_is_dead) { + ipr_trace; + return FAILED; + } + + return SUCCESS; +} + +/** + * ipr_find_ses_entry - Find matching SES in SES table + * @res: resource entry struct of SES + * + * Return value: + * pointer to SES table entry / NULL on failure + **/ +static const struct ipr_ses_table_entry * +ipr_find_ses_entry(struct ipr_resource_entry *res) +{ + int i, j, matches; + const struct ipr_ses_table_entry *ste = ipr_ses_table; + + for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) { + for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) { + if (ste->compare_product_id_byte[j] == 'X') { + if (res->cfgte.std_inq_data.vpids.product_id[j] == ste->product_id[j]) + matches++; + else + break; + } else + matches++; + } + + if (matches == IPR_PROD_ID_LEN) + return ste; + } + + return NULL; +} + +/** + * ipr_get_max_scsi_speed - Determine max SCSI speed for a given bus + * @ioa_cfg: ioa config struct + * @bus: SCSI bus + * @bus_width: bus width + * + * Return value: + * SCSI bus speed in units of 100KHz, 1600 is 160 MHz + * For a 2-byte wide SCSI bus, the maximum transfer speed is + * twice the maximum transfer rate (e.g. for a wide enabled bus, + * max 160MHz = max 320MB/sec). + **/ +static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_width) +{ + struct ipr_resource_entry *res; + const struct ipr_ses_table_entry *ste; + u32 max_xfer_rate = IPR_MAX_SCSI_RATE(bus_width); + + /* Loop through each config table entry in the config table buffer */ + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (!(IPR_IS_SES_DEVICE(res->cfgte.std_inq_data))) + continue; + + if (bus != res->cfgte.res_addr.bus) + continue; + + if (!(ste = ipr_find_ses_entry(res))) + continue; + + max_xfer_rate = (ste->max_bus_speed_limit * 10) / (bus_width / 8); + } + + return max_xfer_rate; +} + +/** + * ipr_wait_iodbg_ack - Wait for an IODEBUG ACK from the IOA + * @ioa_cfg: ioa config struct + * @max_delay: max delay in micro-seconds to wait + * + * Waits for an IODEBUG ACK from the IOA, doing busy looping. + * + * Return value: + * 0 on success / other on failure + **/ +static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay) +{ + volatile u32 pcii_reg; + int delay = 1; + + /* Read interrupt reg until IOA signals IO Debug Acknowledge */ + while (delay < max_delay) { + pcii_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + + if (pcii_reg & IPR_PCII_IO_DEBUG_ACKNOWLEDGE) + return 0; + + /* udelay cannot be used if delay is more than a few milliseconds */ + if ((delay / 1000) > MAX_UDELAY_MS) + mdelay(delay / 1000); + else + udelay(delay); + + delay += delay; + } + return -EIO; +} + +/** + * ipr_get_ldump_data_section - Dump IOA memory + * @ioa_cfg: ioa config struct + * @start_addr: adapter address to dump + * @dest: destination kernel buffer + * @length_in_words: length to dump in 4 byte words + * + * Return value: + * 0 on success / -EIO on failure + **/ +static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, + u32 start_addr, + u32 *dest, u32 length_in_words) +{ + volatile u32 temp_pcii_reg; + int i, delay = 0; + + /* Write IOA interrupt reg starting LDUMP state */ + writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), + ioa_cfg->regs.set_uproc_interrupt_reg); + + /* Wait for IO debug acknowledge */ + if (ipr_wait_iodbg_ack(ioa_cfg, + IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC)) { + dev_err(&ioa_cfg->pdev->dev, + "IOA dump long data transfer timeout\n"); + return -EIO; + } + + /* Signal LDUMP interlocked - clear IO debug ack */ + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, + ioa_cfg->regs.clr_interrupt_reg); + + /* Write Mailbox with starting address */ + writel(start_addr, ioa_cfg->ioa_mailbox); + + /* Signal address valid - clear IOA Reset alert */ + writel(IPR_UPROCI_RESET_ALERT, + ioa_cfg->regs.clr_uproc_interrupt_reg); + + for (i = 0; i < length_in_words; i++) { + /* Wait for IO debug acknowledge */ + if (ipr_wait_iodbg_ack(ioa_cfg, + IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC)) { + dev_err(&ioa_cfg->pdev->dev, + "IOA dump short data transfer timeout\n"); + return -EIO; + } + + /* Read data from mailbox and increment destination pointer */ + *dest = cpu_to_be32(readl(ioa_cfg->ioa_mailbox)); + dest++; + + /* For all but the last word of data, signal data received */ + if (i < (length_in_words - 1)) { + /* Signal dump data received - Clear IO debug Ack */ + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, + ioa_cfg->regs.clr_interrupt_reg); + } + } + + /* Signal end of block transfer. Set reset alert then clear IO debug ack */ + writel(IPR_UPROCI_RESET_ALERT, + ioa_cfg->regs.set_uproc_interrupt_reg); + + writel(IPR_UPROCI_IO_DEBUG_ALERT, + ioa_cfg->regs.clr_uproc_interrupt_reg); + + /* Signal dump data received - Clear IO debug Ack */ + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, + ioa_cfg->regs.clr_interrupt_reg); + + /* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */ + while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) { + temp_pcii_reg = + readl(ioa_cfg->regs.sense_uproc_interrupt_reg); + + if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT)) + return 0; + + udelay(10); + delay += 10; + } + + return 0; +} + +#ifdef CONFIG_SCSI_IPR_DUMP +/** + * ipr_sdt_copy - Copy Smart Dump Table to kernel buffer + * @ioa_cfg: ioa config struct + * @pci_address: adapter address + * @length: length of data to copy + * + * Copy data from PCI adapter to kernel buffer. + * Note: length MUST be a 4 byte multiple + * Return value: + * 0 on success / other on failure + **/ +static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg, + unsigned long pci_address, u32 length) +{ + int bytes_copied = 0; + int cur_len, rc, rem_len, rem_page_len; + u32 *page; + unsigned long lock_flags = 0; + struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump; + + while (bytes_copied < length && + (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) { + if (ioa_dump->page_offset >= PAGE_SIZE || + ioa_dump->page_offset == 0) { + page = (u32 *)__get_free_page(GFP_ATOMIC); + + if (!page) { + ipr_trace; + return bytes_copied; + } + + ioa_dump->page_offset = 0; + ioa_dump->ioa_data[ioa_dump->next_page_index] = page; + ioa_dump->next_page_index++; + } else + page = ioa_dump->ioa_data[ioa_dump->next_page_index - 1]; + + rem_len = length - bytes_copied; + rem_page_len = PAGE_SIZE - ioa_dump->page_offset; + cur_len = min(rem_len, rem_page_len); + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (ioa_cfg->sdt_state == ABORT_DUMP) { + rc = -EIO; + } else { + rc = ipr_get_ldump_data_section(ioa_cfg, + pci_address + bytes_copied, + &page[ioa_dump->page_offset / 4], + (cur_len / sizeof(u32))); + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + if (!rc) { + ioa_dump->page_offset += cur_len; + bytes_copied += cur_len; + } else { + ipr_trace; + break; + } + schedule(); + } + + return bytes_copied; +} + +/** + * ipr_init_dump_entry_hdr - Initialize a dump entry header. + * @hdr: dump entry header struct + * + * Return value: + * nothing + **/ +static void ipr_init_dump_entry_hdr(struct ipr_dump_entry_header *hdr) +{ + hdr->eye_catcher = IPR_DUMP_EYE_CATCHER; + hdr->num_elems = 1; + hdr->offset = sizeof(*hdr); + hdr->status = IPR_DUMP_STATUS_SUCCESS; +} + +/** + * ipr_dump_ioa_type_data - Fill in the adapter type in the dump. + * @ioa_cfg: ioa config struct + * @driver_dump: driver dump struct + * + * Return value: + * nothing + **/ +static void ipr_dump_ioa_type_data(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_driver_dump *driver_dump) +{ + struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; + + ipr_init_dump_entry_hdr(&driver_dump->ioa_type_entry.hdr); + driver_dump->ioa_type_entry.hdr.len = + sizeof(struct ipr_dump_ioa_type_entry) - + sizeof(struct ipr_dump_entry_header); + driver_dump->ioa_type_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; + driver_dump->ioa_type_entry.hdr.id = IPR_DUMP_DRIVER_TYPE_ID; + driver_dump->ioa_type_entry.type = ioa_cfg->type; + driver_dump->ioa_type_entry.fw_version = (ucode_vpd->major_release << 24) | + (ucode_vpd->card_type << 16) | (ucode_vpd->minor_release[0] << 8) | + ucode_vpd->minor_release[1]; + driver_dump->hdr.num_entries++; +} + +/** + * ipr_dump_version_data - Fill in the driver version in the dump. + * @ioa_cfg: ioa config struct + * @driver_dump: driver dump struct + * + * Return value: + * nothing + **/ +static void ipr_dump_version_data(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_driver_dump *driver_dump) +{ + ipr_init_dump_entry_hdr(&driver_dump->version_entry.hdr); + driver_dump->version_entry.hdr.len = + sizeof(struct ipr_dump_version_entry) - + sizeof(struct ipr_dump_entry_header); + driver_dump->version_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; + driver_dump->version_entry.hdr.id = IPR_DUMP_DRIVER_VERSION_ID; + strcpy(driver_dump->version_entry.version, IPR_DRIVER_VERSION); + driver_dump->hdr.num_entries++; +} + +/** + * ipr_dump_trace_data - Fill in the IOA trace in the dump. + * @ioa_cfg: ioa config struct + * @driver_dump: driver dump struct + * + * Return value: + * nothing + **/ +static void ipr_dump_trace_data(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_driver_dump *driver_dump) +{ + ipr_init_dump_entry_hdr(&driver_dump->trace_entry.hdr); + driver_dump->trace_entry.hdr.len = + sizeof(struct ipr_dump_trace_entry) - + sizeof(struct ipr_dump_entry_header); + driver_dump->trace_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; + driver_dump->trace_entry.hdr.id = IPR_DUMP_TRACE_ID; + memcpy(driver_dump->trace_entry.trace, ioa_cfg->trace, IPR_TRACE_SIZE); + driver_dump->hdr.num_entries++; +} + +/** + * ipr_dump_location_data - Fill in the IOA location in the dump. + * @ioa_cfg: ioa config struct + * @driver_dump: driver dump struct + * + * Return value: + * nothing + **/ +static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_driver_dump *driver_dump) +{ + ipr_init_dump_entry_hdr(&driver_dump->location_entry.hdr); + driver_dump->location_entry.hdr.len = + sizeof(struct ipr_dump_location_entry) - + sizeof(struct ipr_dump_entry_header); + driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; + driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID; + strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id); + driver_dump->hdr.num_entries++; +} + +/** + * ipr_get_ioa_dump - Perform a dump of the driver and adapter. + * @ioa_cfg: ioa config struct + * @dump: dump struct + * + * Return value: + * nothing + **/ +static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) +{ + unsigned long start_addr, sdt_word; + unsigned long lock_flags = 0; + struct ipr_driver_dump *driver_dump = &dump->driver_dump; + struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump; + u32 num_entries, start_off, end_off; + u32 bytes_to_copy, bytes_copied, rc; + struct ipr_sdt *sdt; + int i; + + ENTER; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + if (ioa_cfg->sdt_state != GET_DUMP) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + + start_addr = readl(ioa_cfg->ioa_mailbox); + + if (!ipr_sdt_is_fmt2(start_addr)) { + dev_err(&ioa_cfg->pdev->dev, + "Invalid dump table format: %lx\n", start_addr); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + + dev_err(&ioa_cfg->pdev->dev, "Dump of IOA initiated\n"); + + driver_dump->hdr.eye_catcher = IPR_DUMP_EYE_CATCHER; + + /* Initialize the overall dump header */ + driver_dump->hdr.len = sizeof(struct ipr_driver_dump); + driver_dump->hdr.num_entries = 1; + driver_dump->hdr.first_entry_offset = sizeof(struct ipr_dump_header); + driver_dump->hdr.status = IPR_DUMP_STATUS_SUCCESS; + driver_dump->hdr.os = IPR_DUMP_OS_LINUX; + driver_dump->hdr.driver_name = IPR_DUMP_DRIVER_NAME; + + ipr_dump_version_data(ioa_cfg, driver_dump); + ipr_dump_location_data(ioa_cfg, driver_dump); + ipr_dump_ioa_type_data(ioa_cfg, driver_dump); + ipr_dump_trace_data(ioa_cfg, driver_dump); + + /* Update dump_header */ + driver_dump->hdr.len += sizeof(struct ipr_dump_entry_header); + + /* IOA Dump entry */ + ipr_init_dump_entry_hdr(&ioa_dump->hdr); + ioa_dump->format = IPR_SDT_FMT2; + ioa_dump->hdr.len = 0; + ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; + ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID; + + /* First entries in sdt are actually a list of dump addresses and + lengths to gather the real dump data. sdt represents the pointer + to the ioa generated dump table. Dump data will be extracted based + on entries in this table */ + sdt = &ioa_dump->sdt; + + rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (u32 *)sdt, + sizeof(struct ipr_sdt) / sizeof(u32)); + + /* Smart Dump table is ready to use and the first entry is valid */ + if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) { + dev_err(&ioa_cfg->pdev->dev, + "Dump of IOA failed. Dump table not valid: %d, %X.\n", + rc, be32_to_cpu(sdt->hdr.state)); + driver_dump->hdr.status = IPR_DUMP_STATUS_FAILED; + ioa_cfg->sdt_state = DUMP_OBTAINED; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + + num_entries = be32_to_cpu(sdt->hdr.num_entries_used); + + if (num_entries > IPR_NUM_SDT_ENTRIES) + num_entries = IPR_NUM_SDT_ENTRIES; + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + for (i = 0; i < num_entries; i++) { + if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) { + driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; + break; + } + + if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { + sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset); + start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; + end_off = be32_to_cpu(sdt->entry[i].end_offset); + + if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) { + bytes_to_copy = end_off - start_off; + if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { + sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; + continue; + } + + /* Copy data from adapter to driver buffers */ + bytes_copied = ipr_sdt_copy(ioa_cfg, sdt_word, + bytes_to_copy); + + ioa_dump->hdr.len += bytes_copied; + + if (bytes_copied != bytes_to_copy) { + driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; + break; + } + } + } + } + + dev_err(&ioa_cfg->pdev->dev, "Dump of IOA completed.\n"); + + /* Update dump_header */ + driver_dump->hdr.len += ioa_dump->hdr.len; + wmb(); + ioa_cfg->sdt_state = DUMP_OBTAINED; + LEAVE; +} + +#else +#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0) +#endif + +/** + * ipr_worker_thread - Worker thread + * @data: ioa config struct + * + * Called at task level from a work thread. This function takes care + * of adding and removing device from the mid-layer as configuration + * changes are detected by the adapter. + * + * Return value: + * nothing + **/ +static void ipr_worker_thread(void *data) +{ + unsigned long lock_flags; + struct ipr_resource_entry *res; + struct scsi_device *sdev; + struct ipr_dump *dump; + struct ipr_ioa_cfg *ioa_cfg = data; + u8 bus, target, lun; + int did_work; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + if (ioa_cfg->sdt_state == GET_DUMP) { + dump = ioa_cfg->dump; + if (!dump || !kobject_get(&dump->kobj)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + ipr_get_ioa_dump(ioa_cfg, dump); + kobject_put(&dump->kobj); + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (ioa_cfg->sdt_state == DUMP_OBTAINED) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + +restart: + do { + did_work = 0; + if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (res->del_from_ml && res->sdev) { + did_work = 1; + sdev = res->sdev; + if (!scsi_device_get(sdev)) { + res->sdev = NULL; + list_move_tail(&res->queue, &ioa_cfg->free_res_q); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_remove_device(sdev); + scsi_device_put(sdev); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + break; + } + } + } while(did_work); + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (res->add_to_ml) { + bus = res->cfgte.res_addr.bus; + target = res->cfgte.res_addr.target; + lun = res->cfgte.res_addr.lun; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_add_device(ioa_cfg->host, bus, target, lun); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + goto restart; + } + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + LEAVE; +} + +#ifdef CONFIG_SCSI_IPR_TRACE +/** + * ipr_read_trace - Dump the adapter trace + * @kobj: kobject struct + * @buf: buffer + * @off: offset + * @count: buffer size + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_read_trace(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct class_device *cdev = container_of(kobj,struct class_device,kobj); + struct Scsi_Host *shost = class_to_shost(cdev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int size = IPR_TRACE_SIZE; + char *src = (char *)ioa_cfg->trace; + + if (off > size) + return 0; + if (off + count > size) { + size -= off; + count = size; + } + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + memcpy(buf, &src[off], count); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return count; +} + +static struct bin_attribute ipr_trace_attr = { + .attr = { + .name = "trace", + .mode = S_IRUGO, + }, + .size = 0, + .read = ipr_read_trace, +}; +#endif + +/** + * ipr_show_fw_version - Show the firmware version + * @class_dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; + unsigned long lock_flags = 0; + int len; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + len = snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X\n", + ucode_vpd->major_release, ucode_vpd->card_type, + ucode_vpd->minor_release[0], + ucode_vpd->minor_release[1]); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static struct class_device_attribute ipr_fw_version_attr = { + .attr = { + .name = "fw_version", + .mode = S_IRUGO, + }, + .show = ipr_show_fw_version, +}; + +/** + * ipr_show_log_level - Show the adapter's error logging level + * @class_dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int len; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->log_level); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +/** + * ipr_store_log_level - Change the adapter's error logging level + * @class_dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_store_log_level(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->log_level = simple_strtoul(buf, NULL, 10); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return strlen(buf); +} + +static struct class_device_attribute ipr_log_level_attr = { + .attr = { + .name = "log_level", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ipr_show_log_level, + .store = ipr_store_log_level +}; + +/** + * ipr_store_diagnostics - IOA Diagnostics interface + * @class_dev: class_device struct + * @buf: buffer + * @count: buffer size + * + * This function will reset the adapter and wait a reasonable + * amount of time for any errors that the adapter might log. + * + * Return value: + * count on success / other on failure + **/ +static ssize_t ipr_store_diagnostics(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int rc = count; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->errors_logged = 0; + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); + + if (ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + + /* Wait for a second for any errors to be logged */ + schedule_timeout(HZ); + } else { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return -EIO; + } + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (ioa_cfg->in_reset_reload || ioa_cfg->errors_logged) + rc = -EIO; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + return rc; +} + +static struct class_device_attribute ipr_diagnostics_attr = { + .attr = { + .name = "run_diagnostics", + .mode = S_IWUSR, + }, + .store = ipr_store_diagnostics +}; + +/** + * ipr_store_reset_adapter - Reset the adapter + * @class_dev: class_device struct + * @buf: buffer + * @count: buffer size + * + * This function will reset the adapter. + * + * Return value: + * count on success / other on failure + **/ +static ssize_t ipr_store_reset_adapter(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags; + int result = count; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (!ioa_cfg->in_reset_reload) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + + return result; +} + +static struct class_device_attribute ipr_ioa_reset_attr = { + .attr = { + .name = "reset_host", + .mode = S_IWUSR, + }, + .store = ipr_store_reset_adapter +}; + +/** + * ipr_alloc_ucode_buffer - Allocates a microcode download buffer + * @buf_len: buffer length + * + * Allocates a DMA'able buffer in chunks and assembles a scatter/gather + * list to use for microcode download + * + * Return value: + * pointer to sglist / NULL on failure + **/ +static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) +{ + int sg_size, order, bsize_elem, num_elem, i, j; + struct ipr_sglist *sglist; + struct scatterlist *scatterlist; + struct page *page; + + /* Get the minimum size per scatter/gather element */ + sg_size = buf_len / (IPR_MAX_SGLIST - 1); + + /* Get the actual size per element */ + order = get_order(sg_size); + + /* Determine the actual number of bytes per element */ + bsize_elem = PAGE_SIZE * (1 << order); + + /* Determine the actual number of sg entries needed */ + if (buf_len % bsize_elem) + num_elem = (buf_len / bsize_elem) + 1; + else + num_elem = buf_len / bsize_elem; + + /* Allocate a scatter/gather list for the DMA */ + sglist = kmalloc(sizeof(struct ipr_sglist) + + (sizeof(struct scatterlist) * (num_elem - 1)), + GFP_KERNEL); + + if (sglist == NULL) { + ipr_trace; + return NULL; + } + + memset(sglist, 0, sizeof(struct ipr_sglist) + + (sizeof(struct scatterlist) * (num_elem - 1))); + + scatterlist = sglist->scatterlist; + + sglist->order = order; + sglist->num_sg = num_elem; + + /* Allocate a bunch of sg elements */ + for (i = 0; i < num_elem; i++) { + page = alloc_pages(GFP_KERNEL, order); + if (!page) { + ipr_trace; + + /* Free up what we already allocated */ + for (j = i - 1; j >= 0; j--) + __free_pages(scatterlist[j].page, order); + kfree(sglist); + return NULL; + } + + scatterlist[i].page = page; + } + + return sglist; +} + +/** + * ipr_free_ucode_buffer - Frees a microcode download buffer + * @p_dnld: scatter/gather list pointer + * + * Free a DMA'able ucode download buffer previously allocated with + * ipr_alloc_ucode_buffer + * + * Return value: + * nothing + **/ +static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) +{ + int i; + + for (i = 0; i < sglist->num_sg; i++) + __free_pages(sglist->scatterlist[i].page, sglist->order); + + kfree(sglist); +} + +/** + * ipr_copy_ucode_buffer - Copy user buffer to kernel buffer + * @sglist: scatter/gather list pointer + * @buffer: buffer pointer + * @len: buffer length + * + * Copy a microcode image from a user buffer into a buffer allocated by + * ipr_alloc_ucode_buffer + * + * Return value: + * 0 on success / other on failure + **/ +static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, + u8 *buffer, u32 len) +{ + int bsize_elem, i, result = 0; + struct scatterlist *scatterlist; + void *kaddr; + + /* Determine the actual number of bytes per element */ + bsize_elem = PAGE_SIZE * (1 << sglist->order); + + scatterlist = sglist->scatterlist; + + for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { + kaddr = kmap(scatterlist[i].page); + memcpy(kaddr, buffer, bsize_elem); + kunmap(scatterlist[i].page); + + scatterlist[i].length = bsize_elem; + + if (result != 0) { + ipr_trace; + return result; + } + } + + if (len % bsize_elem) { + kaddr = kmap(scatterlist[i].page); + memcpy(kaddr, buffer, len % bsize_elem); + kunmap(scatterlist[i].page); + + scatterlist[i].length = len % bsize_elem; + } + + sglist->buffer_len = len; + return result; +} + +/** + * ipr_map_ucode_buffer - Map a microcode download buffer + * @ipr_cmd: ipr command struct + * @sglist: scatter/gather list + * @len: total length of download buffer + * + * Maps a microcode download scatter/gather list for DMA and + * builds the IOADL. + * + * Return value: + * 0 on success / -EIO on failure + **/ +static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd, + struct ipr_sglist *sglist, int len) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct scatterlist *scatterlist = sglist->scatterlist; + int i; + + ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, scatterlist, + sglist->num_sg, DMA_TO_DEVICE); + + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(len); + ioarcb->write_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + + for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + ioadl[i].flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i])); + ioadl[i].address = + cpu_to_be32(sg_dma_address(&scatterlist[i])); + } + + if (likely(ipr_cmd->dma_use_sg)) { + ioadl[i-1].flags_and_data_len |= + cpu_to_be32(IPR_IOADL_FLAGS_LAST); + } + else { + dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); + return -EIO; + } + + return 0; +} + +/** + * ipr_store_update_fw - Update the firmware on the adapter + * @class_dev: class_device struct + * @buf: buffer + * @count: buffer size + * + * This function will update the firmware on the adapter. + * + * Return value: + * count on success / other on failure + **/ +static ssize_t ipr_store_update_fw(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_ucode_image_header *image_hdr; + const struct firmware *fw_entry; + struct ipr_sglist *sglist; + unsigned long lock_flags; + char fname[100]; + char *src; + int len, result, dnld_size; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + len = snprintf(fname, 99, "%s", buf); + fname[len-1] = '\0'; + + if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { + dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); + return -EIO; + } + + image_hdr = (struct ipr_ucode_image_header *)fw_entry->data; + + if (be32_to_cpu(image_hdr->header_length) > fw_entry->size || + (ioa_cfg->vpd_cbs->page3_data.card_type && + ioa_cfg->vpd_cbs->page3_data.card_type != image_hdr->card_type)) { + dev_err(&ioa_cfg->pdev->dev, "Invalid microcode buffer\n"); + release_firmware(fw_entry); + return -EINVAL; + } + + src = (u8 *)image_hdr + be32_to_cpu(image_hdr->header_length); + dnld_size = fw_entry->size - be32_to_cpu(image_hdr->header_length); + sglist = ipr_alloc_ucode_buffer(dnld_size); + + if (!sglist) { + dev_err(&ioa_cfg->pdev->dev, "Microcode buffer allocation failed\n"); + release_firmware(fw_entry); + return -ENOMEM; + } + + result = ipr_copy_ucode_buffer(sglist, src, dnld_size); + + if (result) { + dev_err(&ioa_cfg->pdev->dev, + "Microcode buffer copy to DMA buffer failed\n"); + ipr_free_ucode_buffer(sglist); + release_firmware(fw_entry); + return result; + } + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + if (ioa_cfg->ucode_sglist) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + dev_err(&ioa_cfg->pdev->dev, + "Microcode download already in progress\n"); + ipr_free_ucode_buffer(sglist); + release_firmware(fw_entry); + return -EIO; + } + + ioa_cfg->ucode_sglist = sglist; + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->ucode_sglist = NULL; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + ipr_free_ucode_buffer(sglist); + release_firmware(fw_entry); + + return count; +} + +static struct class_device_attribute ipr_update_fw_attr = { + .attr = { + .name = "update_fw", + .mode = S_IWUSR, + }, + .store = ipr_store_update_fw +}; + +static struct class_device_attribute *ipr_ioa_attrs[] = { + &ipr_fw_version_attr, + &ipr_log_level_attr, + &ipr_diagnostics_attr, + &ipr_ioa_reset_attr, + &ipr_update_fw_attr, + NULL, +}; + +#ifdef CONFIG_SCSI_IPR_DUMP +/** + * ipr_read_dump - Dump the adapter + * @kobj: kobject struct + * @buf: buffer + * @off: offset + * @count: buffer size + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_read_dump(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct class_device *cdev = container_of(kobj,struct class_device,kobj); + struct Scsi_Host *shost = class_to_shost(cdev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_dump *dump; + unsigned long lock_flags = 0; + char *src; + int len; + size_t rc = count; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + dump = ioa_cfg->dump; + + if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump || !kobject_get(&dump->kobj)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + if (off > dump->driver_dump.hdr.len) { + kobject_put(&dump->kobj); + return 0; + } + + if (off + count > dump->driver_dump.hdr.len) { + count = dump->driver_dump.hdr.len - off; + rc = count; + } + + if (count && off < sizeof(dump->driver_dump)) { + if (off + count > sizeof(dump->driver_dump)) + len = sizeof(dump->driver_dump) - off; + else + len = count; + src = (u8 *)&dump->driver_dump + off; + memcpy(buf, src, len); + buf += len; + off += len; + count -= len; + } + + off -= sizeof(dump->driver_dump); + + if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) { + if (off + count > offsetof(struct ipr_ioa_dump, ioa_data)) + len = offsetof(struct ipr_ioa_dump, ioa_data) - off; + else + len = count; + src = (u8 *)&dump->ioa_dump + off; + memcpy(buf, src, len); + buf += len; + off += len; + count -= len; + } + + off -= offsetof(struct ipr_ioa_dump, ioa_data); + + while (count) { + if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK)) + len = PAGE_ALIGN(off) - off; + else + len = count; + src = (u8 *)dump->ioa_dump.ioa_data[(off & PAGE_MASK) >> PAGE_SHIFT]; + src += off & ~PAGE_MASK; + memcpy(buf, src, len); + buf += len; + off += len; + count -= len; + } + + kobject_put(&dump->kobj); + return rc; +} + +/** + * ipr_release_dump - Free adapter dump memory + * @kobj: kobject struct + * + * Return value: + * nothing + **/ +static void ipr_release_dump(struct kobject *kobj) +{ + struct ipr_dump *dump = container_of(kobj,struct ipr_dump,kobj); + struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; + unsigned long lock_flags = 0; + int i; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ioa_cfg->dump = NULL; + ioa_cfg->sdt_state = INACTIVE; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + for (i = 0; i < dump->ioa_dump.next_page_index; i++) + free_page((unsigned long) dump->ioa_dump.ioa_data[i]); + + kfree(dump); + LEAVE; +} + +static struct kobj_type ipr_dump_kobj_type = { + .release = ipr_release_dump, +}; + +/** + * ipr_alloc_dump - Prepare for adapter dump + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / other on failure + **/ +static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) +{ + struct ipr_dump *dump; + unsigned long lock_flags = 0; + + ENTER; + dump = kmalloc(sizeof(struct ipr_dump), GFP_KERNEL); + + if (!dump) { + ipr_err("Dump memory allocation failed\n"); + return -ENOMEM; + } + + memset(dump, 0, sizeof(struct ipr_dump)); + kobject_init(&dump->kobj); + dump->kobj.ktype = &ipr_dump_kobj_type; + dump->ioa_cfg = ioa_cfg; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + if (INACTIVE != ioa_cfg->sdt_state) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + kfree(dump); + return 0; + } + + ioa_cfg->dump = dump; + ioa_cfg->sdt_state = WAIT_FOR_DUMP; + if (ioa_cfg->ioa_is_dead && !ioa_cfg->dump_taken) { + ioa_cfg->dump_taken = 1; + schedule_work(&ioa_cfg->work_q); + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + LEAVE; + return 0; +} + +/** + * ipr_free_dump - Free adapter dump memory + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / other on failure + **/ +static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) +{ + struct ipr_dump *dump; + unsigned long lock_flags = 0; + + ENTER; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + dump = ioa_cfg->dump; + if (!dump) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; + } + + ioa_cfg->dump = NULL; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + kobject_put(&dump->kobj); + + LEAVE; + return 0; +} + +/** + * ipr_write_dump - Setup dump state of adapter + * @kobj: kobject struct + * @buf: buffer + * @off: offset + * @count: buffer size + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_write_dump(struct kobject *kobj, char *buf, + loff_t off, size_t count) +{ + struct class_device *cdev = container_of(kobj,struct class_device,kobj); + struct Scsi_Host *shost = class_to_shost(cdev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + int rc; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (buf[0] == '1') + rc = ipr_alloc_dump(ioa_cfg); + else if (buf[0] == '0') + rc = ipr_free_dump(ioa_cfg); + else + return -EINVAL; + + if (rc) + return rc; + else + return count; +} + +static struct bin_attribute ipr_dump_attr = { + .attr = { + .name = "dump", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = ipr_read_dump, + .write = ipr_write_dump +}; +#else +static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; +#endif + +/** + * ipr_store_queue_depth - Change the device's queue depth + * @dev: device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_store_queue_depth(struct device *dev, + const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + int qdepth = simple_strtoul(buf, NULL, 10); + int tagged = 0; + unsigned long lock_flags = 0; + ssize_t len = -ENXIO; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + if (res) { + res->qdepth = qdepth; + + if (ipr_is_gscsi(res) && res->tcq_active) + tagged = MSG_ORDERED_TAG; + + len = strlen(buf); + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_adjust_queue_depth(sdev, tagged, qdepth); + return len; +} + +static struct device_attribute ipr_queue_depth_attr = { + .attr = { + .name = "queue_depth", + .mode = S_IRUSR | S_IWUSR, + }, + .store = ipr_store_queue_depth +}; + +/** + * ipr_show_tcq_enable - Show if the device is enabled for tcqing + * @dev: device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_tcq_enable(struct device *dev, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + ssize_t len = -ENXIO; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + if (res) + len = snprintf(buf, PAGE_SIZE, "%d\n", res->tcq_active); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +/** + * ipr_store_tcq_enable - Change the device's TCQing state + * @dev: device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_store_tcq_enable(struct device *dev, + const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + int tcq_active = simple_strtoul(buf, NULL, 10); + int qdepth = IPR_MAX_CMD_PER_LUN; + int tagged = 0; + ssize_t len = -ENXIO; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + res = (struct ipr_resource_entry *)sdev->hostdata; + + if (res) { + res->tcq_active = 0; + qdepth = res->qdepth; + + if (ipr_is_gscsi(res) && sdev->tagged_supported) { + if (tcq_active) { + tagged = MSG_ORDERED_TAG; + res->tcq_active = 1; + } + + len = strlen(buf); + } else if (tcq_active) { + len = -EINVAL; + } + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_adjust_queue_depth(sdev, tagged, qdepth); + return len; +} + +static struct device_attribute ipr_tcqing_attr = { + .attr = { + .name = "tcq_enable", + .mode = S_IRUSR | S_IWUSR, + }, + .store = ipr_store_tcq_enable, + .show = ipr_show_tcq_enable +}; + +/** + * ipr_show_adapter_handle - Show the adapter's resource handle for this device + * @dev: device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_adapter_handle(struct device *dev, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + ssize_t len = -ENXIO; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + if (res) + len = snprintf(buf, PAGE_SIZE, "%08X\n", res->cfgte.res_handle); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static struct device_attribute ipr_adapter_handle_attr = { + .attr = { + .name = "adapter_handle", + .mode = S_IRUSR, + }, + .show = ipr_show_adapter_handle +}; + +static struct device_attribute *ipr_dev_attrs[] = { + &ipr_queue_depth_attr, + &ipr_tcqing_attr, + &ipr_adapter_handle_attr, + NULL, +}; + +/** + * ipr_biosparam - Return the HSC mapping + * @sdev: scsi device struct + * @block_device: block device pointer + * @capacity: capacity of the device + * @parm: Array containing returned HSC values. + * + * This function generates the HSC parms that fdisk uses. + * We want to make sure we return something that places partitions + * on 4k boundaries for best performance with the IOA. + * + * Return value: + * 0 on success + **/ +static int ipr_biosparam(struct scsi_device *sdev, + struct block_device *block_device, + sector_t capacity, int *parm) +{ + int heads, sectors, cylinders; + + heads = 128; + sectors = 32; + + cylinders = capacity; + sector_div(cylinders, (128 * 32)); + + /* return result */ + parm[0] = heads; + parm[1] = sectors; + parm[2] = cylinders; + + return 0; +} + +/** + * ipr_slave_destroy - Unconfigure a SCSI device + * @sdev: scsi device struct + * + * Return value: + * nothing + **/ +static void ipr_slave_destroy(struct scsi_device *sdev) +{ + struct ipr_resource_entry *res; + struct ipr_ioa_cfg *ioa_cfg; + unsigned long lock_flags = 0; + + ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *) sdev->hostdata; + if (res) { + sdev->hostdata = NULL; + res->sdev = NULL; + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +} + +/** + * ipr_slave_configure - Configure a SCSI device + * @sdev: scsi device struct + * + * This function configures the specified scsi device. + * + * Return value: + * 0 on success + **/ +static int ipr_slave_configure(struct scsi_device *sdev) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = sdev->hostdata; + if (res) { + if (ipr_is_af_dasd_device(res)) + sdev->type = TYPE_RAID; + if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) + sdev->scsi_level = 4; + if (ipr_is_vset_device(res)) + sdev->timeout = IPR_VSET_RW_TIMEOUT; + + sdev->allow_restart = 1; + scsi_adjust_queue_depth(sdev, 0, res->qdepth); + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; +} + +/** + * ipr_slave_alloc - Prepare for commands to a device. + * @sdev: scsi device struct + * + * This function saves a pointer to the resource entry + * in the scsi device struct if the device exists. We + * can then use this pointer in ipr_queuecommand when + * handling new commands. + * + * Return value: + * 0 on success + **/ +static int ipr_slave_alloc(struct scsi_device *sdev) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags; + + sdev->hostdata = NULL; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if ((res->cfgte.res_addr.bus == sdev->channel) && + (res->cfgte.res_addr.target == sdev->id) && + (res->cfgte.res_addr.lun == sdev->lun)) { + res->sdev = sdev; + res->add_to_ml = 0; + sdev->hostdata = res; + res->needs_sync_complete = 1; + break; + } + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + return 0; +} + +/** + * ipr_eh_host_reset - Reset the host adapter + * @scsi_cmd: scsi command struct + * + * Return value: + * SUCCESS / FAILED + **/ +static int ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg; + int rc; + + ENTER; + ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; + + dev_err(&ioa_cfg->pdev->dev, + "Adapter being reset as a result of error recovery.\n"); + + if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) + ioa_cfg->sdt_state = GET_DUMP; + + rc = ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV); + + LEAVE; + return rc; +} + +/** + * ipr_eh_dev_reset - Reset the device + * @scsi_cmd: scsi command struct + * + * This function issues a device reset to the affected device. + * A LUN reset will be sent to the device first. If that does + * not work, a target reset will be sent. + * + * Return value: + * SUCCESS / FAILED + **/ +static int ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioa_cfg *ioa_cfg; + struct ipr_resource_entry *res; + struct ipr_cmd_pkt *cmd_pkt; + u32 ioasc; + + ENTER; + ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; + res = scsi_cmd->device->hostdata; + + if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res))) + return FAILED; + + /* + * If we are currently going through reset/reload, return failed. This will force the + * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the + * reset to complete + */ + if (ioa_cfg->in_reset_reload) + return FAILED; + if (ioa_cfg->ioa_is_dead) + return FAILED; + + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { + if (ipr_cmd->scsi_cmd) + ipr_cmd->done = ipr_scsi_eh_done; + } + } + + res->resetting_device = 1; + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + + ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; + cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_RESET_DEVICE; + + ipr_sdev_err(scsi_cmd->device, "Resetting device\n"); + ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); + + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + res->resetting_device = 0; + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + + LEAVE; + return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); +} + +/** + * ipr_bus_reset_done - Op done function for bus reset. + * @ipr_cmd: ipr command struct + * + * This function is the op done function for a bus reset + * + * Return value: + * none + **/ +static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_resource_entry *res; + + ENTER; + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (!memcmp(&res->cfgte.res_handle, &ipr_cmd->ioarcb.res_handle, + sizeof(res->cfgte.res_handle))) { + scsi_report_bus_reset(ioa_cfg->host, res->cfgte.res_addr.bus); + break; + } + } + + /* + * If abort has not completed, indicate the reset has, else call the + * abort's done function to wake the sleeping eh thread + */ + if (ipr_cmd->u.sibling->u.sibling) + ipr_cmd->u.sibling->u.sibling = NULL; + else + ipr_cmd->u.sibling->done(ipr_cmd->u.sibling); + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + LEAVE; +} + +/** + * ipr_abort_timeout - An abort task has timed out + * @ipr_cmd: ipr command struct + * + * This function handles when an abort task times out. If this + * happens we issue a bus reset since we have resources tied + * up that must be freed before returning to the midlayer. + * + * Return value: + * none + **/ +static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_cmnd *reset_cmd; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_cmd_pkt *cmd_pkt; + unsigned long lock_flags = 0; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (ipr_cmd->completion.done || ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return; + } + + ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n"); + reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ipr_cmd->u.sibling = reset_cmd; + reset_cmd->u.sibling = ipr_cmd; + reset_cmd->ioarcb.res_handle = ipr_cmd->ioarcb.res_handle; + cmd_pkt = &reset_cmd->ioarcb.cmd_pkt; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_RESET_DEVICE; + cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET; + + ipr_do_req(reset_cmd, ipr_bus_reset_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + LEAVE; +} + +/** + * ipr_cancel_op - Cancel specified op + * @scsi_cmd: scsi command struct + * + * This function cancels specified op. + * + * Return value: + * SUCCESS / FAILED + **/ +static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioa_cfg *ioa_cfg; + struct ipr_resource_entry *res; + struct ipr_cmd_pkt *cmd_pkt; + u32 ioasc, ioarcb_addr; + int op_found = 0; + + ENTER; + ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; + res = scsi_cmd->device->hostdata; + + if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res))) + return FAILED; + + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->scsi_cmd == scsi_cmd) { + ipr_cmd->done = ipr_scsi_eh_done; + op_found = 1; + break; + } + } + + if (!op_found) + return SUCCESS; + + ioarcb_addr = be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr); + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; + cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_ABORT_TASK; + cmd_pkt->cdb[2] = (ioarcb_addr >> 24) & 0xff; + cmd_pkt->cdb[3] = (ioarcb_addr >> 16) & 0xff; + cmd_pkt->cdb[4] = (ioarcb_addr >> 8) & 0xff; + cmd_pkt->cdb[5] = ioarcb_addr & 0xff; + ipr_cmd->u.sdev = scsi_cmd->device; + + ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); + ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_ABORT_TASK_TIMEOUT); + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + /* + * If the abort task timed out and we sent a bus reset, we will get + * one the following responses to the abort + */ + if (ioasc == IPR_IOASC_BUS_WAS_RESET || ioasc == IPR_IOASC_SYNC_REQUIRED) { + ioasc = 0; + ipr_trace; + } + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + res->needs_sync_complete = 1; + + LEAVE; + return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); +} + +/** + * ipr_eh_abort - Abort a single op + * @scsi_cmd: scsi command struct + * + * Return value: + * SUCCESS / FAILED + **/ +static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg; + + ENTER; + ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; + + /* If we are currently going through reset/reload, return failed. This will force the + mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the + reset to complete */ + if (ioa_cfg->in_reset_reload) + return FAILED; + if (ioa_cfg->ioa_is_dead) + return FAILED; + if (!scsi_cmd->device->hostdata) + return FAILED; + + LEAVE; + return ipr_cancel_op(scsi_cmd); +} + +/** + * ipr_handle_other_interrupt - Handle "other" interrupts + * @ioa_cfg: ioa config struct + * @int_reg: interrupt register + * + * Return value: + * IRQ_NONE / IRQ_HANDLED + **/ +static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, + volatile u32 int_reg) +{ + irqreturn_t rc = IRQ_HANDLED; + + if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { + /* Mask the interrupt */ + writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.set_interrupt_mask_reg); + + /* Clear the interrupt */ + writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + + list_del(&ioa_cfg->reset_cmd->queue); + del_timer(&ioa_cfg->reset_cmd->timer); + ipr_reset_ioa_job(ioa_cfg->reset_cmd); + } else { + if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) + ioa_cfg->ioa_unit_checked = 1; + else + dev_err(&ioa_cfg->pdev->dev, + "Permanent IOA failure. 0x%08X\n", int_reg); + + if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) + ioa_cfg->sdt_state = GET_DUMP; + + ipr_mask_and_clear_interrupts(ioa_cfg, ~0); + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + } + + return rc; +} + +/** + * ipr_isr - Interrupt service routine + * @irq: irq number + * @devp: pointer to ioa config struct + * @regs: pt_regs struct + * + * Return value: + * IRQ_NONE / IRQ_HANDLED + **/ +static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; + unsigned long lock_flags = 0; + volatile u32 int_reg, int_mask_reg; + u32 ioasc; + u16 cmd_index; + struct ipr_cmnd *ipr_cmd; + irqreturn_t rc = IRQ_NONE; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + /* If interrupts are disabled, ignore the interrupt */ + if (!ioa_cfg->allow_interrupts) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return IRQ_NONE; + } + + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + + /* If an interrupt on the adapter did not occur, ignore it */ + if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return IRQ_NONE; + } + + while (1) { + ipr_cmd = NULL; + + while ((be32_to_cpu(*ioa_cfg->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) == + ioa_cfg->toggle_bit) { + + cmd_index = (be32_to_cpu(*ioa_cfg->hrrq_curr) & + IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT; + + if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) { + ioa_cfg->errors_logged++; + dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n"); + + if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) + ioa_cfg->sdt_state = GET_DUMP; + + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return IRQ_HANDLED; + } + + ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index]; + + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc); + + list_del(&ipr_cmd->queue); + del_timer(&ipr_cmd->timer); + ipr_cmd->done(ipr_cmd); + + rc = IRQ_HANDLED; + + if (ioa_cfg->hrrq_curr < ioa_cfg->hrrq_end) { + ioa_cfg->hrrq_curr++; + } else { + ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; + ioa_cfg->toggle_bit ^= 1u; + } + } + + if (ipr_cmd != NULL) { + /* Clear the PCI interrupt */ + writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + } else + break; + } + + if (unlikely(rc == IRQ_NONE)) + rc = ipr_handle_other_interrupt(ioa_cfg, int_reg); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return rc; +} + +/** + * ipr_build_ioadl - Build a scatter/gather list and map the buffer + * @ioa_cfg: ioa config struct + * @ipr_cmd: ipr command struct + * + * Return value: + * 0 on success / -1 on failure + **/ +static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_cmnd *ipr_cmd) +{ + int i; + struct scatterlist *sglist; + u32 length; + u32 ioadl_flags = 0; + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + + length = scsi_cmd->request_bufflen; + + if (length == 0) + return 0; + + if (scsi_cmd->use_sg) { + ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, + scsi_cmd->request_buffer, + scsi_cmd->use_sg, + scsi_cmd->sc_data_direction); + + if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_WRITE; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(length); + ioarcb->write_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_READ; + ioarcb->read_data_transfer_length = cpu_to_be32(length); + ioarcb->read_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } + + sglist = scsi_cmd->request_buffer; + + for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + ioadl[i].flags_and_data_len = + cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i])); + ioadl[i].address = + cpu_to_be32(sg_dma_address(&sglist[i])); + } + + if (likely(ipr_cmd->dma_use_sg)) { + ioadl[i-1].flags_and_data_len |= + cpu_to_be32(IPR_IOADL_FLAGS_LAST); + return 0; + } else + dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); + } else { + if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_WRITE; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(length); + ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_READ; + ioarcb->read_data_transfer_length = cpu_to_be32(length); + ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + } + + ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev, + scsi_cmd->request_buffer, length, + scsi_cmd->sc_data_direction); + + if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) { + ipr_cmd->dma_use_sg = 1; + ioadl[0].flags_and_data_len = + cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST); + ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle); + return 0; + } else + dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n"); + } + + return -1; +} + +/** + * ipr_get_task_attributes - Translate SPI Q-Tag to task attributes + * @scsi_cmd: scsi command struct + * + * Return value: + * task attributes + **/ +static u8 ipr_get_task_attributes(struct scsi_cmnd *scsi_cmd) +{ + u8 tag[2]; + u8 rc = IPR_FLAGS_LO_UNTAGGED_TASK; + + if (scsi_populate_tag_msg(scsi_cmd, tag)) { + switch (tag[0]) { + case MSG_SIMPLE_TAG: + rc = IPR_FLAGS_LO_SIMPLE_TASK; + break; + case MSG_HEAD_TAG: + rc = IPR_FLAGS_LO_HEAD_OF_Q_TASK; + break; + case MSG_ORDERED_TAG: + rc = IPR_FLAGS_LO_ORDERED_TASK; + break; + }; + } + + return rc; +} + +/** + * ipr_erp_done - Process completion of ERP for a device + * @ipr_cmd: ipr command struct + * + * This function copies the sense buffer into the scsi_cmd + * struct and pushes the scsi_done function. + * + * Return value: + * nothing + **/ +static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) +{ + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + struct ipr_resource_entry *res = scsi_cmd->device->hostdata; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { + scsi_cmd->result |= (DID_ERROR << 16); + ipr_sdev_err(scsi_cmd->device, + "Request Sense failed with IOASC: 0x%08X\n", ioasc); + } else { + memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE); + } + + if (res) + res->needs_sync_complete = 1; + ipr_unmap_sglist(ioa_cfg, ipr_cmd); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + scsi_cmd->scsi_done(scsi_cmd); +} + +/** + * ipr_reinit_ipr_cmnd_for_erp - Re-initialize a cmnd block to be used for ERP + * @ipr_cmd: ipr command struct + * + * Return value: + * none + **/ +static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioarcb *ioarcb; + struct ipr_ioasa *ioasa; + + ioarcb = &ipr_cmd->ioarcb; + ioasa = &ipr_cmd->ioasa; + + memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); + ioarcb->write_data_transfer_length = 0; + ioarcb->read_data_transfer_length = 0; + ioarcb->write_ioadl_len = 0; + ioarcb->read_ioadl_len = 0; + ioasa->ioasc = 0; + ioasa->residual_data_len = 0; +} + +/** + * ipr_erp_request_sense - Send request sense to a device + * @ipr_cmd: ipr command struct + * + * This function sends a request sense to a device as a result + * of a check condition. + * + * Return value: + * nothing + **/ +static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; + + ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); + + cmd_pkt->request_type = IPR_RQTYPE_SCSICDB; + cmd_pkt->cdb[0] = REQUEST_SENSE; + cmd_pkt->cdb[4] = SCSI_SENSE_BUFFERSIZE; + cmd_pkt->flags_hi |= IPR_FLAGS_HI_SYNC_OVERRIDE; + cmd_pkt->flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; + cmd_pkt->timeout = cpu_to_be16(IPR_REQUEST_SENSE_TIMEOUT / HZ); + + ipr_cmd->ioadl[0].flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | SCSI_SENSE_BUFFERSIZE); + ipr_cmd->ioadl[0].address = + cpu_to_be32(ipr_cmd->sense_buffer_dma); + + ipr_cmd->ioarcb.read_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ipr_cmd->ioarcb.read_data_transfer_length = + cpu_to_be32(SCSI_SENSE_BUFFERSIZE); + + ipr_do_req(ipr_cmd, ipr_erp_done, ipr_timeout, + IPR_REQUEST_SENSE_TIMEOUT * 2); +} + +/** + * ipr_erp_cancel_all - Send cancel all to a device + * @ipr_cmd: ipr command struct + * + * This function sends a cancel all to a device to clear the + * queue. If we are running TCQ on the device, QERR is set to 1, + * which means all outstanding ops have been dropped on the floor. + * Cancel all will return them to us. + * + * Return value: + * nothing + **/ +static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) +{ + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + struct ipr_resource_entry *res = scsi_cmd->device->hostdata; + struct ipr_cmd_pkt *cmd_pkt; + + res->in_erp = 1; + + ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); + + cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; + + ipr_do_req(ipr_cmd, ipr_erp_request_sense, ipr_timeout, + IPR_CANCEL_ALL_TIMEOUT); +} + +/** + * ipr_dump_ioasa - Dump contents of IOASA + * @ioa_cfg: ioa config struct + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler when ops + * fail. It will log the IOASA if appropriate. Only called + * for GPDD ops. + * + * Return value: + * none + **/ +static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_cmnd *ipr_cmd) +{ + int i; + u16 data_len; + u32 ioasc; + struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + u32 *ioasa_data = (u32 *)ioasa; + int error_index; + + ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK; + + if (0 == ioasc) + return; + + if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) + return; + + error_index = ipr_get_error(ioasc); + + if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) { + /* Don't log an error if the IOA already logged one */ + if (ioasa->ilid != 0) + return; + + if (ipr_error_table[error_index].log_ioasa == 0) + return; + } + + ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n", + ipr_error_table[error_index].error); + + if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) && + (ioasa->u.gpdd.bus_phase <= ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) { + ipr_sdev_err(ipr_cmd->scsi_cmd->device, + "Device End state: %s Phase: %s\n", + ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state], + ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]); + } + + if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len)) + data_len = sizeof(struct ipr_ioasa); + else + data_len = be16_to_cpu(ioasa->ret_stat_len); + + ipr_err("IOASA Dump:\n"); + + for (i = 0; i < data_len / 4; i += 4) { + ipr_err("%08X: %08X %08X %08X %08X\n", i*4, + be32_to_cpu(ioasa_data[i]), + be32_to_cpu(ioasa_data[i+1]), + be32_to_cpu(ioasa_data[i+2]), + be32_to_cpu(ioasa_data[i+3])); + } +} + +/** + * ipr_gen_sense - Generate SCSI sense data from an IOASA + * @ioasa: IOASA + * @sense_buf: sense data buffer + * + * Return value: + * none + **/ +static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd) +{ + u32 failing_lba; + u8 *sense_buf = ipr_cmd->scsi_cmd->sense_buffer; + struct ipr_resource_entry *res = ipr_cmd->scsi_cmd->device->hostdata; + struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + u32 ioasc = be32_to_cpu(ioasa->ioasc); + + memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); + + if (ioasc >= IPR_FIRST_DRIVER_IOASC) + return; + + ipr_cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; + + if (ipr_is_vset_device(res) && + ioasc == IPR_IOASC_MED_DO_NOT_REALLOC && + ioasa->u.vset.failing_lba_hi != 0) { + sense_buf[0] = 0x72; + sense_buf[1] = IPR_IOASC_SENSE_KEY(ioasc); + sense_buf[2] = IPR_IOASC_SENSE_CODE(ioasc); + sense_buf[3] = IPR_IOASC_SENSE_QUAL(ioasc); + + sense_buf[7] = 12; + sense_buf[8] = 0; + sense_buf[9] = 0x0A; + sense_buf[10] = 0x80; + + failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_hi); + + sense_buf[12] = (failing_lba & 0xff000000) >> 24; + sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; + sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; + sense_buf[15] = failing_lba & 0x000000ff; + + failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); + + sense_buf[16] = (failing_lba & 0xff000000) >> 24; + sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; + sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; + sense_buf[19] = failing_lba & 0x000000ff; + } else { + sense_buf[0] = 0x70; + sense_buf[2] = IPR_IOASC_SENSE_KEY(ioasc); + sense_buf[12] = IPR_IOASC_SENSE_CODE(ioasc); + sense_buf[13] = IPR_IOASC_SENSE_QUAL(ioasc); + + /* Illegal request */ + if ((IPR_IOASC_SENSE_KEY(ioasc) == 0x05) && + (be32_to_cpu(ioasa->ioasc_specific) & IPR_FIELD_POINTER_VALID)) { + sense_buf[7] = 10; /* additional length */ + + /* IOARCB was in error */ + if (IPR_IOASC_SENSE_CODE(ioasc) == 0x24) + sense_buf[15] = 0xC0; + else /* Parameter data was invalid */ + sense_buf[15] = 0x80; + + sense_buf[16] = + ((IPR_FIELD_POINTER_MASK & + be32_to_cpu(ioasa->ioasc_specific)) >> 8) & 0xff; + sense_buf[17] = + (IPR_FIELD_POINTER_MASK & + be32_to_cpu(ioasa->ioasc_specific)) & 0xff; + } else { + if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) { + if (ipr_is_vset_device(res)) + failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); + else + failing_lba = be32_to_cpu(ioasa->u.dasd.failing_lba); + + sense_buf[0] |= 0x80; /* Or in the Valid bit */ + sense_buf[3] = (failing_lba & 0xff000000) >> 24; + sense_buf[4] = (failing_lba & 0x00ff0000) >> 16; + sense_buf[5] = (failing_lba & 0x0000ff00) >> 8; + sense_buf[6] = failing_lba & 0x000000ff; + } + + sense_buf[7] = 6; /* additional length */ + } + } +} + +/** + * ipr_erp_start - Process an error response for a SCSI op + * @ioa_cfg: ioa config struct + * @ipr_cmd: ipr command struct + * + * This function determines whether or not to initiate ERP + * on the affected device. + * + * Return value: + * nothing + **/ +static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_cmnd *ipr_cmd) +{ + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + struct ipr_resource_entry *res = scsi_cmd->device->hostdata; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (!res) { + ipr_scsi_eh_done(ipr_cmd); + return; + } + + if (ipr_is_gscsi(res)) + ipr_dump_ioasa(ioa_cfg, ipr_cmd); + else + ipr_gen_sense(ipr_cmd); + + switch (ioasc & IPR_IOASC_IOASC_MASK) { + case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: + scsi_cmd->result |= (DID_ERROR << 16); + break; + case IPR_IOASC_IR_RESOURCE_HANDLE: + scsi_cmd->result |= (DID_NO_CONNECT << 16); + break; + case IPR_IOASC_HW_SEL_TIMEOUT: + scsi_cmd->result |= (DID_NO_CONNECT << 16); + res->needs_sync_complete = 1; + break; + case IPR_IOASC_SYNC_REQUIRED: + if (!res->in_erp) + res->needs_sync_complete = 1; + scsi_cmd->result |= (DID_IMM_RETRY << 16); + break; + case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */ + scsi_cmd->result |= (DID_PASSTHROUGH << 16); + break; + case IPR_IOASC_BUS_WAS_RESET: + case IPR_IOASC_BUS_WAS_RESET_BY_OTHER: + /* + * Report the bus reset and ask for a retry. The device + * will give CC/UA the next command. + */ + if (!res->resetting_device) + scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel); + scsi_cmd->result |= (DID_ERROR << 16); + res->needs_sync_complete = 1; + break; + case IPR_IOASC_HW_DEV_BUS_STATUS: + scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc); + if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) { + ipr_erp_cancel_all(ipr_cmd); + return; + } + break; + case IPR_IOASC_NR_INIT_CMD_REQUIRED: + break; + default: + scsi_cmd->result |= (DID_ERROR << 16); + if (!ipr_is_vset_device(res)) + res->needs_sync_complete = 1; + break; + } + + ipr_unmap_sglist(ioa_cfg, ipr_cmd); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + scsi_cmd->scsi_done(scsi_cmd); +} + +/** + * ipr_scsi_done - mid-layer done function + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler for + * ops generated by the SCSI mid-layer + * + * Return value: + * none + **/ +static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len); + + if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) { + ipr_unmap_sglist(ioa_cfg, ipr_cmd); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + scsi_cmd->scsi_done(scsi_cmd); + } else + ipr_erp_start(ioa_cfg, ipr_cmd); +} + +/** + * ipr_save_ioafp_mode_select - Save adapters mode select data + * @ioa_cfg: ioa config struct + * @scsi_cmd: scsi command struct + * + * This function saves mode select data for the adapter to + * use following an adapter reset. + * + * Return value: + * 0 on success / SCSI_MLQUEUE_HOST_BUSY on failure + **/ +static int ipr_save_ioafp_mode_select(struct ipr_ioa_cfg *ioa_cfg, + struct scsi_cmnd *scsi_cmd) +{ + if (!ioa_cfg->saved_mode_pages) { + ioa_cfg->saved_mode_pages = kmalloc(sizeof(struct ipr_mode_pages), + GFP_ATOMIC); + if (!ioa_cfg->saved_mode_pages) { + dev_err(&ioa_cfg->pdev->dev, + "IOA mode select buffer allocation failed\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + + memcpy(ioa_cfg->saved_mode_pages, scsi_cmd->buffer, scsi_cmd->cmnd[4]); + ioa_cfg->saved_mode_page_len = scsi_cmd->cmnd[4]; + return 0; +} + +/** + * ipr_queuecommand - Queue a mid-layer request + * @scsi_cmd: scsi command struct + * @done: done function + * + * This function queues a request generated by the mid-layer. + * + * Return value: + * 0 on success + * SCSI_MLQUEUE_DEVICE_BUSY if device is busy + * SCSI_MLQUEUE_HOST_BUSY if host is busy + **/ +static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, + void (*done) (struct scsi_cmnd *)) +{ + struct ipr_ioa_cfg *ioa_cfg; + struct ipr_resource_entry *res; + struct ipr_ioarcb *ioarcb; + struct ipr_cmnd *ipr_cmd; + int rc = 0; + + scsi_cmd->scsi_done = done; + ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; + res = scsi_cmd->device->hostdata; + scsi_cmd->result = (DID_OK << 16); + + /* + * We are currently blocking all devices due to a host reset + * We have told the host to stop giving us new requests, but + * ERP ops don't count. FIXME + */ + if (unlikely(!ioa_cfg->allow_cmds)) + return SCSI_MLQUEUE_HOST_BUSY; + + /* + * FIXME - Create scsi_set_host_offline interface + * and the ioa_is_dead check can be removed + */ + if (unlikely(ioa_cfg->ioa_is_dead || !res)) { + memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + scsi_cmd->result = (DID_NO_CONNECT << 16); + scsi_cmd->scsi_done(scsi_cmd); + return 0; + } + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioarcb = &ipr_cmd->ioarcb; + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + + memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); + ipr_cmd->scsi_cmd = scsi_cmd; + ioarcb->res_handle = res->cfgte.res_handle; + ipr_cmd->done = ipr_scsi_done; + ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr)); + + if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { + if (scsi_cmd->underflow == 0) + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; + + if (res->needs_sync_complete) { + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE; + res->needs_sync_complete = 0; + } + + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; + ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd); + } + + if (!ipr_is_gscsi(res) && scsi_cmd->cmnd[0] >= 0xC0) + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; + + if (ipr_is_ioa_resource(res) && scsi_cmd->cmnd[0] == MODE_SELECT) + rc = ipr_save_ioafp_mode_select(ioa_cfg, scsi_cmd); + + if (likely(rc == 0)) + rc = ipr_build_ioadl(ioa_cfg, ipr_cmd); + + if (likely(rc == 0)) { + mb(); + writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), + ioa_cfg->regs.ioarrin_reg); + } else { + list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + return SCSI_MLQUEUE_HOST_BUSY; + } + + return 0; +} + +/** + * ipr_info - Get information about the card/driver + * @scsi_host: scsi host struct + * + * Return value: + * pointer to buffer with description string + **/ +static const char * ipr_ioa_info(struct Scsi_Host *host) +{ + static char buffer[512]; + struct ipr_ioa_cfg *ioa_cfg; + unsigned long lock_flags = 0; + + ioa_cfg = (struct ipr_ioa_cfg *) host->hostdata; + + spin_lock_irqsave(host->host_lock, lock_flags); + sprintf(buffer, "IBM %X Storage Adapter", ioa_cfg->type); + spin_unlock_irqrestore(host->host_lock, lock_flags); + + return buffer; +} + +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = "IPR", + .info = ipr_ioa_info, + .queuecommand = ipr_queuecommand, + .eh_abort_handler = ipr_eh_abort, + .eh_device_reset_handler = ipr_eh_dev_reset, + .eh_host_reset_handler = ipr_eh_host_reset, + .slave_alloc = ipr_slave_alloc, + .slave_configure = ipr_slave_configure, + .slave_destroy = ipr_slave_destroy, + .bios_param = ipr_biosparam, + .can_queue = IPR_MAX_COMMANDS, + .this_id = -1, + .sg_tablesize = IPR_MAX_SGLIST, + .max_sectors = IPR_MAX_SECTORS, + .cmd_per_lun = IPR_MAX_CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = ipr_ioa_attrs, + .sdev_attrs = ipr_dev_attrs, + .proc_name = IPR_NAME +}; + +#ifdef CONFIG_PPC_PSERIES +static const u16 ipr_blocked_processors[] = { + PV_NORTHSTAR, + PV_PULSAR, + PV_POWER4, + PV_ICESTAR, + PV_SSTAR, + PV_POWER4p, + PV_630, + PV_630p +}; + +/** + * ipr_invalid_adapter - Determine if this adapter is supported on this hardware + * @ioa_cfg: ioa cfg struct + * + * Adapters that use Gemstone revision < 3.1 do not work reliably on + * certain pSeries hardware. This function determines if the given + * adapter is in one of these confgurations or not. + * + * Return value: + * 1 if adapter is not supported / 0 if adapter is supported + **/ +static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) +{ + u8 rev_id; + int i; + + if (ioa_cfg->type == 0x5702) { + if (pci_read_config_byte(ioa_cfg->pdev, PCI_REVISION_ID, + &rev_id) == PCIBIOS_SUCCESSFUL) { + if (rev_id < 4) { + for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ + if (__is_processor(ipr_blocked_processors[i])) + return 1; + } + } + } + } + return 0; +} +#else +#define ipr_invalid_adapter(ioa_cfg) 0 +#endif + +/** + * ipr_ioa_bringdown_done - IOA bring down completion. + * @ipr_cmd: ipr command struct + * + * This function processes the completion of an adapter bring down. + * It wakes any reset sleepers. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioa_bringdown_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + ioa_cfg->in_reset_reload = 0; + ioa_cfg->reset_retries = 0; + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + wake_up_all(&ioa_cfg->reset_wait_q); + + spin_unlock_irq(ioa_cfg->host->host_lock); + scsi_unblock_requests(ioa_cfg->host); + spin_lock_irq(ioa_cfg->host->host_lock); + LEAVE; + + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_ioa_reset_done - IOA reset completion. + * @ipr_cmd: ipr command struct + * + * This function processes the completion of an adapter reset. + * It schedules any necessary mid-layer add/removes and + * wakes any reset sleepers. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_resource_entry *res; + struct ipr_hostrcb *hostrcb, *temp; + int i = 0; + + ENTER; + ioa_cfg->in_reset_reload = 0; + ioa_cfg->allow_cmds = 1; + ioa_cfg->reset_cmd = NULL; + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) { + ipr_trace; + schedule_work(&ioa_cfg->work_q); + break; + } + } + + list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) { + list_del(&hostrcb->queue); + if (i++ < IPR_NUM_LOG_HCAMS) + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); + else + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); + } + + dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n"); + + ioa_cfg->reset_retries = 0; + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + wake_up_all(&ioa_cfg->reset_wait_q); + + spin_unlock_irq(ioa_cfg->host->host_lock); + scsi_unblock_requests(ioa_cfg->host); + spin_lock_irq(ioa_cfg->host->host_lock); + + if (!ioa_cfg->allow_cmds) + scsi_block_requests(ioa_cfg->host); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_set_sup_dev_dflt - Initialize a Set Supported Device buffer + * @supported_dev: supported device struct + * @vpids: vendor product id struct + * + * Return value: + * none + **/ +static void ipr_set_sup_dev_dflt(struct ipr_supported_device *supported_dev, + struct ipr_std_inq_vpids *vpids) +{ + memset(supported_dev, 0, sizeof(struct ipr_supported_device)); + memcpy(&supported_dev->vpids, vpids, sizeof(struct ipr_std_inq_vpids)); + supported_dev->num_records = 1; + supported_dev->data_length = + cpu_to_be16(sizeof(struct ipr_supported_device)); + supported_dev->reserved = 0; +} + +/** + * ipr_set_supported_devs - Send Set Supported Devices for a device + * @ipr_cmd: ipr command struct + * + * This function send a Set Supported Devices to the adapter + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_resource_entry *res = ipr_cmd->u.res; + + ipr_cmd->job_step = ipr_ioa_reset_done; + + list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { + if (!ipr_is_af_dasd_device(res)) + continue; + + ipr_cmd->u.res = res; + ipr_set_sup_dev_dflt(supp_dev, &res->cfgte.std_inq_data.vpids); + + ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; + + ioarcb->cmd_pkt.cdb[0] = IPR_SET_SUPPORTED_DEVICES; + ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_supported_device) >> 8) & 0xff; + ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_supported_device) & 0xff; + + ioadl->flags_and_data_len = cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | + sizeof(struct ipr_supported_device)); + ioadl->address = cpu_to_be32(ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, supp_dev)); + ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ioarcb->write_data_transfer_length = + cpu_to_be32(sizeof(struct ipr_supported_device)); + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, + IPR_SET_SUP_DEVICE_TIMEOUT); + + ipr_cmd->job_step = ipr_set_supported_devs; + return IPR_RC_JOB_RETURN; + } + + return IPR_RC_JOB_CONTINUE; +} + +/** + * ipr_get_mode_page - Locate specified mode page + * @mode_pages: mode page buffer + * @page_code: page code to find + * @len: minimum required length for mode page + * + * Return value: + * pointer to mode page / NULL on failure + **/ +static void *ipr_get_mode_page(struct ipr_mode_pages *mode_pages, + u32 page_code, u32 len) +{ + struct ipr_mode_page_hdr *mode_hdr; + u32 page_length; + u32 length; + + if (!mode_pages || (mode_pages->hdr.length == 0)) + return NULL; + + length = (mode_pages->hdr.length + 1) - 4 - mode_pages->hdr.block_desc_len; + mode_hdr = (struct ipr_mode_page_hdr *) + (mode_pages->data + mode_pages->hdr.block_desc_len); + + while (length) { + if (IPR_GET_MODE_PAGE_CODE(mode_hdr) == page_code) { + if (mode_hdr->page_length >= (len - sizeof(struct ipr_mode_page_hdr))) + return mode_hdr; + break; + } else { + page_length = (sizeof(struct ipr_mode_page_hdr) + + mode_hdr->page_length); + length -= page_length; + mode_hdr = (struct ipr_mode_page_hdr *) + ((unsigned long)mode_hdr + page_length); + } + } + return NULL; +} + +/** + * ipr_check_term_power - Check for term power errors + * @ioa_cfg: ioa config struct + * @mode_pages: IOAFP mode pages buffer + * + * Check the IOAFP's mode page 28 for term power errors + * + * Return value: + * nothing + **/ +static void ipr_check_term_power(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_mode_pages *mode_pages) +{ + int i; + int entry_length; + struct ipr_dev_bus_entry *bus; + struct ipr_mode_page28 *mode_page; + + mode_page = ipr_get_mode_page(mode_pages, 0x28, + sizeof(struct ipr_mode_page28)); + + entry_length = mode_page->entry_length; + + bus = mode_page->bus; + + for (i = 0; i < mode_page->num_entries; i++) { + if (bus->flags & IPR_SCSI_ATTR_NO_TERM_PWR) { + dev_err(&ioa_cfg->pdev->dev, + "Term power is absent on scsi bus %d\n", + bus->res_addr.bus); + } + + bus = (struct ipr_dev_bus_entry *)((char *)bus + entry_length); + } +} + +/** + * ipr_scsi_bus_speed_limit - Limit the SCSI speed based on SES table + * @ioa_cfg: ioa config struct + * + * Looks through the config table checking for SES devices. If + * the SES device is in the SES table indicating a maximum SCSI + * bus speed, the speed is limited for the bus. + * + * Return value: + * none + **/ +static void ipr_scsi_bus_speed_limit(struct ipr_ioa_cfg *ioa_cfg) +{ + u32 max_xfer_rate; + int i; + + for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { + max_xfer_rate = ipr_get_max_scsi_speed(ioa_cfg, i, + ioa_cfg->bus_attr[i].bus_width); + + if (max_xfer_rate < ioa_cfg->bus_attr[i].max_xfer_rate) + ioa_cfg->bus_attr[i].max_xfer_rate = max_xfer_rate; + } +} + +/** + * ipr_modify_ioafp_mode_page_28 - Modify IOAFP Mode Page 28 + * @ioa_cfg: ioa config struct + * @mode_pages: mode page 28 buffer + * + * Updates mode page 28 based on driver configuration + * + * Return value: + * none + **/ +static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_mode_pages *mode_pages) +{ + int i, entry_length; + struct ipr_dev_bus_entry *bus; + struct ipr_bus_attributes *bus_attr; + struct ipr_mode_page28 *mode_page; + + mode_page = ipr_get_mode_page(mode_pages, 0x28, + sizeof(struct ipr_mode_page28)); + + entry_length = mode_page->entry_length; + + /* Loop for each device bus entry */ + for (i = 0, bus = mode_page->bus; + i < mode_page->num_entries; + i++, bus = (struct ipr_dev_bus_entry *)((u8 *)bus + entry_length)) { + if (bus->res_addr.bus > IPR_MAX_NUM_BUSES) { + dev_err(&ioa_cfg->pdev->dev, + "Invalid resource address reported: 0x%08X\n", + IPR_GET_PHYS_LOC(bus->res_addr)); + continue; + } + + bus_attr = &ioa_cfg->bus_attr[i]; + bus->extended_reset_delay = IPR_EXTENDED_RESET_DELAY; + bus->bus_width = bus_attr->bus_width; + bus->max_xfer_rate = cpu_to_be32(bus_attr->max_xfer_rate); + bus->flags &= ~IPR_SCSI_ATTR_QAS_MASK; + if (bus_attr->qas_enabled) + bus->flags |= IPR_SCSI_ATTR_ENABLE_QAS; + else + bus->flags |= IPR_SCSI_ATTR_DISABLE_QAS; + } +} + +/** + * ipr_build_mode_select - Build a mode select command + * @ipr_cmd: ipr command struct + * @res_handle: resource handle to send command to + * @parm: Byte 2 of Mode Sense command + * @dma_addr: DMA buffer address + * @xfer_len: data transfer length + * + * Return value: + * none + **/ +static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd, + u32 res_handle, u8 parm, u32 dma_addr, + u8 xfer_len) +{ + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + + ioarcb->res_handle = res_handle; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->cmd_pkt.cdb[0] = MODE_SELECT; + ioarcb->cmd_pkt.cdb[1] = parm; + ioarcb->cmd_pkt.cdb[4] = xfer_len; + + ioadl->flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | xfer_len); + ioadl->address = cpu_to_be32(dma_addr); + ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ioarcb->write_data_transfer_length = cpu_to_be32(xfer_len); +} + +/** + * ipr_ioafp_mode_select_page28 - Issue Mode Select Page 28 to IOA + * @ipr_cmd: ipr command struct + * + * This function sets up the SCSI bus attributes and sends + * a Mode Select for Page 28 to activate them. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; + int length; + + ENTER; + if (ioa_cfg->saved_mode_pages) { + memcpy(mode_pages, ioa_cfg->saved_mode_pages, + ioa_cfg->saved_mode_page_len); + length = ioa_cfg->saved_mode_page_len; + } else { + ipr_scsi_bus_speed_limit(ioa_cfg); + ipr_check_term_power(ioa_cfg, mode_pages); + ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages); + length = mode_pages->hdr.length + 1; + mode_pages->hdr.length = 0; + } + + ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), + length); + + ipr_cmd->job_step = ipr_set_supported_devs; + ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next, + struct ipr_resource_entry, queue); + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_build_mode_sense - Builds a mode sense command + * @ipr_cmd: ipr command struct + * @res: resource entry struct + * @parm: Byte 2 of mode sense command + * @dma_addr: DMA address of mode sense buffer + * @xfer_len: Size of DMA buffer + * + * Return value: + * none + **/ +static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd, + u32 res_handle, + u8 parm, u32 dma_addr, u8 xfer_len) +{ + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + + ioarcb->res_handle = res_handle; + ioarcb->cmd_pkt.cdb[0] = MODE_SENSE; + ioarcb->cmd_pkt.cdb[2] = parm; + ioarcb->cmd_pkt.cdb[4] = xfer_len; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; + + ioadl->flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len); + ioadl->address = cpu_to_be32(dma_addr); + ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len); +} + +/** + * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA + * @ipr_cmd: ipr command struct + * + * This function send a Page 28 mode sense to the IOA to + * retrieve SCSI bus attributes. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), + 0x28, ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, mode_pages), + sizeof(struct ipr_mode_pages)); + + ipr_cmd->job_step = ipr_ioafp_mode_select_page28; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_init_res_table - Initialize the resource table + * @ipr_cmd: ipr command struct + * + * This function looks through the existing resource table, comparing + * it with the config table. This function will take care of old/new + * devices and schedule adding/removing them from the mid-layer + * as appropriate. + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_resource_entry *res, *temp; + struct ipr_config_table_entry *cfgte; + int found, i; + LIST_HEAD(old_res); + + ENTER; + if (ioa_cfg->cfg_table->hdr.flags & IPR_UCODE_DOWNLOAD_REQ) + dev_err(&ioa_cfg->pdev->dev, "Microcode download required\n"); + + list_for_each_entry_safe(res, temp, &ioa_cfg->used_res_q, queue) + list_move_tail(&res->queue, &old_res); + + for (i = 0; i < ioa_cfg->cfg_table->hdr.num_entries; i++) { + cfgte = &ioa_cfg->cfg_table->dev[i]; + found = 0; + + list_for_each_entry_safe(res, temp, &old_res, queue) { + if (!memcmp(&res->cfgte.res_addr, + &cfgte->res_addr, sizeof(cfgte->res_addr))) { + list_move_tail(&res->queue, &ioa_cfg->used_res_q); + found = 1; + break; + } + } + + if (!found) { + if (list_empty(&ioa_cfg->free_res_q)) { + dev_err(&ioa_cfg->pdev->dev, "Too many devices attached\n"); + break; + } + + found = 1; + res = list_entry(ioa_cfg->free_res_q.next, + struct ipr_resource_entry, queue); + list_move_tail(&res->queue, &ioa_cfg->used_res_q); + ipr_init_res_entry(res); + res->add_to_ml = 1; + } + + if (found) + memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry)); + } + + list_for_each_entry_safe(res, temp, &old_res, queue) { + if (res->sdev) { + res->del_from_ml = 1; + list_move_tail(&res->queue, &ioa_cfg->used_res_q); + } else { + list_move_tail(&res->queue, &ioa_cfg->free_res_q); + } + } + + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** + * ipr_ioafp_query_ioa_cfg - Send a Query IOA Config to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Query IOA Configuration command + * to the adapter to retrieve the IOA configuration table. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; + + ENTER; + dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n", + ucode_vpd->major_release, ucode_vpd->card_type, + ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]); + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; + ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + + ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG; + ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_config_table) >> 8) & 0xff; + ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_config_table) & 0xff; + + ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ioarcb->read_data_transfer_length = + cpu_to_be32(sizeof(struct ipr_config_table)); + + ioadl->address = cpu_to_be32(ioa_cfg->cfg_table_dma); + ioadl->flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(struct ipr_config_table)); + + ipr_cmd->job_step = ipr_init_res_table; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_ioafp_inquiry - Send an Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This utility function sends an inquiry to the adapter. + * + * Return value: + * none + **/ +static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page, + u32 dma_addr, u8 xfer_len) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + + ENTER; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; + ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + + ioarcb->cmd_pkt.cdb[0] = INQUIRY; + ioarcb->cmd_pkt.cdb[1] = flags; + ioarcb->cmd_pkt.cdb[2] = page; + ioarcb->cmd_pkt.cdb[4] = xfer_len; + + ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); + ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len); + + ioadl->address = cpu_to_be32(dma_addr); + ioadl->flags_and_data_len = + cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len); + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + LEAVE; +} + +/** + * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Page 3 inquiry to the adapter + * to retrieve software VPD information. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + char type[5]; + + ENTER; + + /* Grab the type out of the VPD and store it away */ + memcpy(type, ioa_cfg->vpd_cbs->ioa_vpd.std_inq_data.vpids.product_id, 4); + type[4] = '\0'; + ioa_cfg->type = simple_strtoul((char *)type, NULL, 16); + + ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + + ipr_ioafp_inquiry(ipr_cmd, 1, 3, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data), + sizeof(struct ipr_inquiry_page3)); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_ioafp_std_inquiry - Send a Standard Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a standard inquiry to the adapter. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_page3_inquiry; + + ipr_ioafp_inquiry(ipr_cmd, 0, 0, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, ioa_vpd), + sizeof(struct ipr_ioa_vpd)); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_ioafp_indentify_hrrq - Send Identify Host RRQ. + * @ipr_cmd: ipr command struct + * + * This function send an Identify Host Request Response Queue + * command to establish the HRRQ with the adapter. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + + ENTER; + dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n"); + + ioarcb->cmd_pkt.cdb[0] = IPR_ID_HOST_RR_Q; + ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; + ioarcb->cmd_pkt.cdb[2] = + ((u32) ioa_cfg->host_rrq_dma >> 24) & 0xff; + ioarcb->cmd_pkt.cdb[3] = + ((u32) ioa_cfg->host_rrq_dma >> 16) & 0xff; + ioarcb->cmd_pkt.cdb[4] = + ((u32) ioa_cfg->host_rrq_dma >> 8) & 0xff; + ioarcb->cmd_pkt.cdb[5] = + ((u32) ioa_cfg->host_rrq_dma) & 0xff; + ioarcb->cmd_pkt.cdb[7] = + ((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff; + ioarcb->cmd_pkt.cdb[8] = + (sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff; + + ipr_cmd->job_step = ipr_ioafp_std_inquiry; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_timer_done - Adapter reset timer function + * @ipr_cmd: ipr command struct + * + * Description: This function is used in adapter reset processing + * for timing events. If the reset_cmd pointer in the IOA + * config struct is not this adapter's we are doing nested + * resets and fail_all_ops will take care of freeing the + * command block. + * + * Return value: + * none + **/ +static void ipr_reset_timer_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + if (ioa_cfg->reset_cmd == ipr_cmd) { + list_del(&ipr_cmd->queue); + ipr_cmd->done(ipr_cmd); + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +} + +/** + * ipr_reset_start_timer - Start a timer for adapter reset job + * @ipr_cmd: ipr command struct + * @timeout: timeout value + * + * Description: This function is used in adapter reset processing + * for timing events. If the reset_cmd pointer in the IOA + * config struct is not this adapter's we are doing nested + * resets and fail_all_ops will take care of freeing the + * command block. + * + * Return value: + * none + **/ +static void ipr_reset_start_timer(struct ipr_cmnd *ipr_cmd, + unsigned long timeout) +{ + list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); + ipr_cmd->done = ipr_reset_ioa_job; + + ipr_cmd->timer.data = (unsigned long) ipr_cmd; + ipr_cmd->timer.expires = jiffies + timeout; + ipr_cmd->timer.function = (void (*)(unsigned long))ipr_reset_timer_done; + add_timer(&ipr_cmd->timer); +} + +/** + * ipr_init_ioa_mem - Initialize ioa_cfg control block + * @ioa_cfg: ioa cfg struct + * + * Return value: + * nothing + **/ +static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg) +{ + memset(ioa_cfg->host_rrq, 0, sizeof(u32) * IPR_NUM_CMD_BLKS); + + /* Initialize Host RRQ pointers */ + ioa_cfg->hrrq_start = ioa_cfg->host_rrq; + ioa_cfg->hrrq_end = &ioa_cfg->host_rrq[IPR_NUM_CMD_BLKS - 1]; + ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; + ioa_cfg->toggle_bit = 1; + + /* Zero out config table */ + memset(ioa_cfg->cfg_table, 0, sizeof(struct ipr_config_table)); +} + +/** + * ipr_reset_enable_ioa - Enable the IOA following a reset. + * @ipr_cmd: ipr command struct + * + * This function reinitializes some control blocks and + * enables destructive diagnostics on the adapter. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + volatile u32 int_reg; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_indentify_hrrq; + ipr_init_ioa_mem(ioa_cfg); + + ioa_cfg->allow_interrupts = 1; + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + + if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { + writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED), + ioa_cfg->regs.clr_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + return IPR_RC_JOB_CONTINUE; + } + + /* Enable destructive diagnostics on IOA */ + writel(IPR_DOORBELL, ioa_cfg->regs.set_uproc_interrupt_reg); + + writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + + dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n"); + + ipr_cmd->timer.data = (unsigned long) ipr_cmd; + ipr_cmd->timer.expires = jiffies + IPR_OPERATIONAL_TIMEOUT; + ipr_cmd->timer.function = (void (*)(unsigned long))ipr_timeout; + add_timer(&ipr_cmd->timer); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_wait_for_dump - Wait for a dump to timeout. + * @ipr_cmd: ipr command struct + * + * This function is invoked when an adapter dump has run out + * of processing time. + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_wait_for_dump(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + if (ioa_cfg->sdt_state == GET_DUMP) + ioa_cfg->sdt_state = ABORT_DUMP; + + ipr_cmd->job_step = ipr_reset_alert; + + return IPR_RC_JOB_CONTINUE; +} + +/** + * ipr_unit_check_no_data - Log a unit check/no data error log + * @ioa_cfg: ioa config struct + * + * Logs an error indicating the adapter unit checked, but for some + * reason, we were unable to fetch the unit check buffer. + * + * Return value: + * nothing + **/ +static void ipr_unit_check_no_data(struct ipr_ioa_cfg *ioa_cfg) +{ + ioa_cfg->errors_logged++; + dev_err(&ioa_cfg->pdev->dev, "IOA unit check with no data\n"); +} + +/** + * ipr_get_unit_check_buffer - Get the unit check buffer from the IOA + * @ioa_cfg: ioa config struct + * + * Fetches the unit check buffer from the adapter by clocking the data + * through the mailbox register. + * + * Return value: + * nothing + **/ +static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) +{ + unsigned long mailbox; + struct ipr_hostrcb *hostrcb; + struct ipr_uc_sdt sdt; + int rc, length; + + mailbox = readl(ioa_cfg->ioa_mailbox); + + if (!ipr_sdt_is_fmt2(mailbox)) { + ipr_unit_check_no_data(ioa_cfg); + return; + } + + memset(&sdt, 0, sizeof(struct ipr_uc_sdt)); + rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (u32 *) &sdt, + (sizeof(struct ipr_uc_sdt)) / sizeof(u32)); + + if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) || + !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) { + ipr_unit_check_no_data(ioa_cfg); + return; + } + + /* Find length of the first sdt entry (UC buffer) */ + length = (be32_to_cpu(sdt.entry[0].end_offset) - + be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK; + + hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, + struct ipr_hostrcb, queue); + list_del(&hostrcb->queue); + memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); + + rc = ipr_get_ldump_data_section(ioa_cfg, + be32_to_cpu(sdt.entry[0].bar_str_offset), + (u32 *)&hostrcb->hcam, + min(length, (int)sizeof(hostrcb->hcam)) / sizeof(u32)); + + if (!rc) + ipr_handle_log_data(ioa_cfg, hostrcb); + else + ipr_unit_check_no_data(ioa_cfg); + + list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); +} + +/** + * ipr_reset_restore_cfg_space - Restore PCI config space. + * @ipr_cmd: ipr command struct + * + * Description: This function restores the saved PCI config space of + * the adapter, fails all outstanding ops back to the callers, and + * fetches the dump/unit check if applicable to this reset. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + int rc; + + ENTER; + rc = pci_restore_state(ioa_cfg->pdev, ioa_cfg->pci_cfg_buf); + + if (rc != PCIBIOS_SUCCESSFUL) { + ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + return IPR_RC_JOB_CONTINUE; + } + + if (ipr_set_pcix_cmd_reg(ioa_cfg)) { + ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + return IPR_RC_JOB_CONTINUE; + } + + ipr_fail_all_ops(ioa_cfg); + + if (ioa_cfg->ioa_unit_checked) { + ioa_cfg->ioa_unit_checked = 0; + ipr_get_unit_check_buffer(ioa_cfg); + ipr_cmd->job_step = ipr_reset_alert; + ipr_reset_start_timer(ipr_cmd, 0); + return IPR_RC_JOB_RETURN; + } + + if (ioa_cfg->in_ioa_bringdown) { + ipr_cmd->job_step = ipr_ioa_bringdown_done; + } else { + ipr_cmd->job_step = ipr_reset_enable_ioa; + + if (GET_DUMP == ioa_cfg->sdt_state) { + ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT); + ipr_cmd->job_step = ipr_reset_wait_for_dump; + schedule_work(&ioa_cfg->work_q); + return IPR_RC_JOB_RETURN; + } + } + + ENTER; + return IPR_RC_JOB_CONTINUE; +} + +/** + * ipr_reset_start_bist - Run BIST on the adapter. + * @ipr_cmd: ipr command struct + * + * Description: This function runs BIST on the adapter, then delays 2 seconds. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + int rc; + + ENTER; + rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); + + if (rc != PCIBIOS_SUCCESSFUL) { + ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + rc = IPR_RC_JOB_CONTINUE; + } else { + ipr_cmd->job_step = ipr_reset_restore_cfg_space; + ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); + rc = IPR_RC_JOB_RETURN; + } + + LEAVE; + return rc; +} + +/** + * ipr_reset_allowed - Query whether or not IOA can be reset + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 if reset not allowed / non-zero if reset is allowed + **/ +static int ipr_reset_allowed(struct ipr_ioa_cfg *ioa_cfg) +{ + volatile u32 temp_reg; + + temp_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + return ((temp_reg & IPR_PCII_CRITICAL_OPERATION) == 0); +} + +/** + * ipr_reset_wait_to_start_bist - Wait for permission to reset IOA. + * @ipr_cmd: ipr command struct + * + * Description: This function waits for adapter permission to run BIST, + * then runs BIST. If the adapter does not give permission after a + * reasonable time, we will reset the adapter anyway. The impact of + * resetting the adapter without warning the adapter is the risk of + * losing the persistent error log on the adapter. If the adapter is + * reset while it is writing to the flash on the adapter, the flash + * segment will have bad ECC and be zeroed. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + int rc = IPR_RC_JOB_RETURN; + + if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->u.time_left) { + ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); + } else { + ipr_cmd->job_step = ipr_reset_start_bist; + rc = IPR_RC_JOB_CONTINUE; + } + + return rc; +} + +/** + * ipr_reset_alert_part2 - Alert the adapter of a pending reset + * @ipr_cmd: ipr command struct + * + * Description: This function alerts the adapter that it will be reset. + * If memory space is not currently enabled, proceed directly + * to running BIST on the adapter. The timer must always be started + * so we guarantee we do not run BIST from ipr_isr. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + u16 cmd_reg; + int rc; + + ENTER; + rc = pci_read_config_word(ioa_cfg->pdev, PCI_COMMAND, &cmd_reg); + + if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) { + ipr_mask_and_clear_interrupts(ioa_cfg, ~0); + writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg); + ipr_cmd->job_step = ipr_reset_wait_to_start_bist; + } else { + ipr_cmd->job_step = ipr_reset_start_bist; + } + + ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_ucode_download_done - Microcode download completion + * @ipr_cmd: ipr command struct + * + * Description: This function unmaps the microcode download buffer. + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_ucode_download_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; + + pci_unmap_sg(ioa_cfg->pdev, sglist->scatterlist, + sglist->num_sg, DMA_TO_DEVICE); + + ipr_cmd->job_step = ipr_reset_alert; + return IPR_RC_JOB_CONTINUE; +} + +/** + * ipr_reset_ucode_download - Download microcode to the adapter + * @ipr_cmd: ipr command struct + * + * Description: This function checks to see if it there is microcode + * to download to the adapter. If there is, a download is performed. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; + + ENTER; + ipr_cmd->job_step = ipr_reset_alert; + + if (!sglist) + return IPR_RC_JOB_CONTINUE; + + ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; + ipr_cmd->ioarcb.cmd_pkt.cdb[0] = WRITE_BUFFER; + ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_WR_BUF_DOWNLOAD_AND_SAVE; + ipr_cmd->ioarcb.cmd_pkt.cdb[6] = (sglist->buffer_len & 0xff0000) >> 16; + ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8; + ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff; + + if (ipr_map_ucode_buffer(ipr_cmd, sglist, sglist->buffer_len)) { + dev_err(&ioa_cfg->pdev->dev, + "Failed to map microcode download buffer\n"); + return IPR_RC_JOB_CONTINUE; + } + + ipr_cmd->job_step = ipr_reset_ucode_download_done; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, + IPR_WRITE_BUFFER_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_shutdown_ioa - Shutdown the adapter + * @ipr_cmd: ipr command struct + * + * Description: This function issues an adapter shutdown of the + * specified type to the specified adapter as part of the + * adapter reset job. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + enum ipr_shutdown_type shutdown_type = ipr_cmd->u.shutdown_type; + unsigned long timeout; + int rc = IPR_RC_JOB_CONTINUE; + + ENTER; + if (shutdown_type != IPR_SHUTDOWN_NONE && !ioa_cfg->ioa_is_dead) { + ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); + ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD; + ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; + ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type; + + if (shutdown_type == IPR_SHUTDOWN_ABBREV) + timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; + else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL) + timeout = IPR_INTERNAL_TIMEOUT; + else + timeout = IPR_SHUTDOWN_TIMEOUT; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout); + + rc = IPR_RC_JOB_RETURN; + ipr_cmd->job_step = ipr_reset_ucode_download; + } else + ipr_cmd->job_step = ipr_reset_alert; + + LEAVE; + return rc; +} + +/** + * ipr_reset_ioa_job - Adapter reset job + * @ipr_cmd: ipr command struct + * + * Description: This function is the job router for the adapter reset job. + * + * Return value: + * none + **/ +static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) +{ + u32 rc, ioasc; + unsigned long scratch = ipr_cmd->u.scratch; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + do { + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (ioa_cfg->reset_cmd != ipr_cmd) { + /* + * We are doing nested adapter resets and this is + * not the current reset job. + */ + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + return; + } + + if (IPR_IOASC_SENSE_KEY(ioasc)) { + dev_err(&ioa_cfg->pdev->dev, + "0x%02X failed with IOASC: 0x%08X\n", + ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc); + + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + return; + } + + ipr_reinit_ipr_cmnd(ipr_cmd); + ipr_cmd->u.scratch = scratch; + rc = ipr_cmd->job_step(ipr_cmd); + } while(rc == IPR_RC_JOB_CONTINUE); +} + +/** + * _ipr_initiate_ioa_reset - Initiate an adapter reset + * @ioa_cfg: ioa config struct + * @job_step: first job step of reset job + * @shutdown_type: shutdown type + * + * Description: This function will initiate the reset of the given adapter + * starting at the selected job step. + * If the caller needs to wait on the completion of the reset, + * the caller must sleep on the reset_wait_q. + * + * Return value: + * none + **/ +static void _ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, + int (*job_step) (struct ipr_cmnd *), + enum ipr_shutdown_type shutdown_type) +{ + struct ipr_cmnd *ipr_cmd; + + ioa_cfg->in_reset_reload = 1; + ioa_cfg->allow_cmds = 0; + scsi_block_requests(ioa_cfg->host); + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioa_cfg->reset_cmd = ipr_cmd; + ipr_cmd->job_step = job_step; + ipr_cmd->u.shutdown_type = shutdown_type; + + ipr_reset_ioa_job(ipr_cmd); +} + +/** + * ipr_initiate_ioa_reset - Initiate an adapter reset + * @ioa_cfg: ioa config struct + * @shutdown_type: shutdown type + * + * Description: This function will initiate the reset of the given adapter. + * If the caller needs to wait on the completion of the reset, + * the caller must sleep on the reset_wait_q. + * + * Return value: + * none + **/ +static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, + enum ipr_shutdown_type shutdown_type) +{ + if (ioa_cfg->ioa_is_dead) + return; + + if (ioa_cfg->in_reset_reload && ioa_cfg->sdt_state == GET_DUMP) + ioa_cfg->sdt_state = ABORT_DUMP; + + if (ioa_cfg->reset_retries++ > IPR_NUM_RESET_RELOAD_RETRIES) { + dev_err(&ioa_cfg->pdev->dev, + "IOA taken offline - error recovery failed\n"); + + ioa_cfg->reset_retries = 0; + ioa_cfg->ioa_is_dead = 1; + + if (ioa_cfg->in_ioa_bringdown) { + ioa_cfg->reset_cmd = NULL; + ioa_cfg->in_reset_reload = 0; + ipr_fail_all_ops(ioa_cfg); + wake_up_all(&ioa_cfg->reset_wait_q); + + spin_unlock_irq(ioa_cfg->host->host_lock); + scsi_unblock_requests(ioa_cfg->host); + spin_lock_irq(ioa_cfg->host->host_lock); + return; + } else { + ioa_cfg->in_ioa_bringdown = 1; + shutdown_type = IPR_SHUTDOWN_NONE; + } + } + + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_shutdown_ioa, + shutdown_type); +} + +/** + * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) + * @ioa_cfg: ioa cfg struct + * + * Description: This is the second phase of adapter intialization + * This function takes care of initilizing the adapter to the point + * where it can accept new commands. + + * Return value: + * 0 on sucess / -EIO on failure + **/ +static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg) +{ + int rc = 0; + unsigned long host_lock_flags = 0; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg); + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, IPR_SHUTDOWN_NONE); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + + if (ioa_cfg->ioa_is_dead) { + rc = -EIO; + } else if (ipr_invalid_adapter(ioa_cfg)) { + if (!ipr_testmode) + rc = -EIO; + + dev_err(&ioa_cfg->pdev->dev, + "Adapter not supported in this hardware configuration.\n"); + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + + LEAVE; + return rc; +} + +/** + * ipr_free_cmd_blks - Frees command blocks allocated for an adapter + * @ioa_cfg: ioa config struct + * + * Return value: + * none + **/ +static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) +{ + int i; + + for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { + if (ioa_cfg->ipr_cmnd_list[i]) + pci_pool_free(ioa_cfg->ipr_cmd_pool, + ioa_cfg->ipr_cmnd_list[i], + ioa_cfg->ipr_cmnd_list_dma[i]); + + ioa_cfg->ipr_cmnd_list[i] = NULL; + } + + if (ioa_cfg->ipr_cmd_pool) + pci_pool_destroy (ioa_cfg->ipr_cmd_pool); + + ioa_cfg->ipr_cmd_pool = NULL; +} + +/** + * ipr_free_mem - Frees memory allocated for an adapter + * @ioa_cfg: ioa cfg struct + * + * Return value: + * nothing + **/ +static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) +{ + int i; + + kfree(ioa_cfg->res_entries); + pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_misc_cbs), + ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); + ipr_free_cmd_blks(ioa_cfg); + pci_free_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, + ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); + pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table), + ioa_cfg->cfg_table, + ioa_cfg->cfg_table_dma); + + for (i = 0; i < IPR_NUM_HCAMS; i++) { + pci_free_consistent(ioa_cfg->pdev, + sizeof(struct ipr_hostrcb), + ioa_cfg->hostrcb[i], + ioa_cfg->hostrcb_dma[i]); + } + + ipr_free_dump(ioa_cfg); + kfree(ioa_cfg->saved_mode_pages); + kfree(ioa_cfg->trace); +} + +/** + * ipr_free_all_resources - Free all allocated resources for an adapter. + * @ipr_cmd: ipr command struct + * + * This function frees all allocated resources for the + * specified adapter. + * + * Return value: + * none + **/ +static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) +{ + ENTER; + free_irq(ioa_cfg->pdev->irq, ioa_cfg); + iounmap((void *) ioa_cfg->hdw_dma_regs); + release_mem_region(ioa_cfg->hdw_dma_regs_pci, + pci_resource_len(ioa_cfg->pdev, 0)); + ipr_free_mem(ioa_cfg); + scsi_host_put(ioa_cfg->host); + LEAVE; +} + +/** + * ipr_alloc_cmd_blks - Allocate command blocks for an adapter + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / -ENOMEM on allocation failure + **/ +static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + u32 dma_addr; + int i; + + ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, + sizeof(struct ipr_cmnd), 8, 0); + + if (!ioa_cfg->ipr_cmd_pool) + return -ENOMEM; + + for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { + ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, SLAB_KERNEL, &dma_addr); + + if (!ipr_cmd) { + ipr_free_cmd_blks(ioa_cfg); + return -ENOMEM; + } + + memset(ipr_cmd, 0, sizeof(*ipr_cmd)); + ioa_cfg->ipr_cmnd_list[i] = ipr_cmd; + ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr; + + ioarcb = &ipr_cmd->ioarcb; + ioarcb->ioarcb_host_pci_addr = cpu_to_be32(dma_addr); + ioarcb->host_response_handle = cpu_to_be32(i << 2); + ioarcb->write_ioadl_addr = + cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); + ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; + ioarcb->ioasa_host_pci_addr = + cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa)); + ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa)); + ipr_cmd->cmd_index = i; + ipr_cmd->ioa_cfg = ioa_cfg; + ipr_cmd->sense_buffer_dma = dma_addr + + offsetof(struct ipr_cmnd, sense_buffer); + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + } + + return 0; +} + +/** + * ipr_alloc_mem - Allocate memory for an adapter + * @ioa_cfg: ioa config struct + * + * Return value: + * 0 on success / non-zero for error + **/ +static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) +{ + int i; + + ENTER; + ioa_cfg->res_entries = kmalloc(sizeof(struct ipr_resource_entry) * + IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL); + + if (!ioa_cfg->res_entries) + goto cleanup; + + memset(ioa_cfg->res_entries, 0, + sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS); + + for (i = 0; i < IPR_MAX_PHYSICAL_DEVS; i++) + list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q); + + ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev, + sizeof(struct ipr_misc_cbs), + &ioa_cfg->vpd_cbs_dma); + + if (!ioa_cfg->vpd_cbs) + goto cleanup; + + if (ipr_alloc_cmd_blks(ioa_cfg)) + goto cleanup; + + ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev, + sizeof(u32) * IPR_NUM_CMD_BLKS, + &ioa_cfg->host_rrq_dma); + + if (!ioa_cfg->host_rrq) + goto cleanup; + + ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev, + sizeof(struct ipr_config_table), + &ioa_cfg->cfg_table_dma); + + if (!ioa_cfg->cfg_table) + goto cleanup; + + for (i = 0; i < IPR_NUM_HCAMS; i++) { + ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev, + sizeof(struct ipr_hostrcb), + &ioa_cfg->hostrcb_dma[i]); + + if (!ioa_cfg->hostrcb[i]) + goto cleanup; + + memset(ioa_cfg->hostrcb[i], 0, sizeof(struct ipr_hostrcb)); + ioa_cfg->hostrcb[i]->hostrcb_dma = + ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); + list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); + } + + ioa_cfg->trace = kmalloc(sizeof(struct ipr_trace_entry) * + IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); + + if (!ioa_cfg->trace) + goto cleanup; + + memset(ioa_cfg->trace, 0, + sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES); + + LEAVE; + return 0; + +cleanup: + ipr_free_mem(ioa_cfg); + + LEAVE; + return -ENOMEM; +} + +/** + * ipr_initialize_bus_attr - Initialize SCSI bus attributes to default values + * @ioa_cfg: ioa config struct + * + * Return value: + * none + **/ +static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg) +{ + int i; + + for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { + ioa_cfg->bus_attr[i].bus = i; + ioa_cfg->bus_attr[i].qas_enabled = 0; + ioa_cfg->bus_attr[i].bus_width = IPR_DEFAULT_BUS_WIDTH; + if (ipr_max_speed < ARRAY_SIZE(ipr_max_bus_speeds)) + ioa_cfg->bus_attr[i].max_xfer_rate = ipr_max_bus_speeds[ipr_max_speed]; + else + ioa_cfg->bus_attr[i].max_xfer_rate = IPR_U160_SCSI_RATE; + } +} + +/** + * ipr_init_ioa_cfg - Initialize IOA config struct + * @ioa_cfg: ioa config struct + * @host: scsi host struct + * @pdev: PCI dev struct + * + * Return value: + * none + **/ +static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, + struct Scsi_Host *host, struct pci_dev *pdev) +{ + ioa_cfg->host = host; + ioa_cfg->pdev = pdev; + ioa_cfg->log_level = ipr_log_level; + sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER); + sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL); + sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL); + sprintf(ioa_cfg->ipr_pending_label, IPR_PENDQ_LABEL); + sprintf(ioa_cfg->cfg_table_start, IPR_CFG_TBL_START); + sprintf(ioa_cfg->resource_table_label, IPR_RES_TABLE_LABEL); + sprintf(ioa_cfg->ipr_hcam_label, IPR_HCAM_LABEL); + sprintf(ioa_cfg->ipr_cmd_label, IPR_CMD_LABEL); + + INIT_LIST_HEAD(&ioa_cfg->free_q); + INIT_LIST_HEAD(&ioa_cfg->pending_q); + INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q); + INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); + INIT_LIST_HEAD(&ioa_cfg->free_res_q); + INIT_LIST_HEAD(&ioa_cfg->used_res_q); + INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg); + init_waitqueue_head(&ioa_cfg->reset_wait_q); + ioa_cfg->sdt_state = INACTIVE; + + ipr_initialize_bus_attr(ioa_cfg); + + host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS; + host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET; + host->max_channel = IPR_MAX_BUS_TO_SCAN; + host->unique_id = host->host_no; + host->max_cmd_len = IPR_MAX_CDB_LEN; + pci_set_drvdata(pdev, ioa_cfg); + + memcpy(&ioa_cfg->regs, &ioa_cfg->chip_cfg->regs, sizeof(ioa_cfg->regs)); + + ioa_cfg->regs.set_interrupt_mask_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.clr_interrupt_mask_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.sense_interrupt_mask_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.clr_interrupt_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.sense_interrupt_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.ioarrin_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.sense_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.set_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs; + ioa_cfg->regs.clr_uproc_interrupt_reg += ioa_cfg->hdw_dma_regs; +} + +/** + * ipr_probe_ioa - Allocates memory and does first stage of initialization + * @pdev: PCI device struct + * @dev_id: PCI device id struct + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int __devinit ipr_probe_ioa(struct pci_dev *pdev, + const struct pci_device_id *dev_id) +{ + struct ipr_ioa_cfg *ioa_cfg; + struct Scsi_Host *host; + unsigned long ipr_regs, ipr_regs_pci; + u32 rc = PCIBIOS_SUCCESSFUL; + + ENTER; + + if ((rc = pci_enable_device(pdev))) { + dev_err(&pdev->dev, "Cannot enable adapter\n"); + return rc; + } + + dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); + + host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); + + if (!host) { + dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n"); + return -ENOMEM; + } + + ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; + memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); + + ioa_cfg->chip_cfg = (const struct ipr_chip_cfg_t *)dev_id->driver_data; + + ipr_regs_pci = pci_resource_start(pdev, 0); + + if (!request_mem_region(ipr_regs_pci, + pci_resource_len(pdev, 0), IPR_NAME)) { + dev_err(&pdev->dev, + "Couldn't register memory range of registers\n"); + scsi_host_put(host); + return -ENOMEM; + } + + ipr_regs = (unsigned long)ioremap(ipr_regs_pci, + pci_resource_len(pdev, 0)); + + if (!ipr_regs) { + dev_err(&pdev->dev, + "Couldn't map memory range of registers\n"); + release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); + scsi_host_put(host); + return -ENOMEM; + } + + ioa_cfg->hdw_dma_regs = ipr_regs; + ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci; + ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs; + + ipr_init_ioa_cfg(ioa_cfg, host, pdev); + + pci_set_master(pdev); + rc = pci_set_dma_mask(pdev, 0xffffffff); + + if (rc != PCIBIOS_SUCCESSFUL) { + dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); + rc = -EIO; + goto cleanup_nomem; + } + + rc = pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, + ioa_cfg->chip_cfg->cache_line_size); + + if (rc != PCIBIOS_SUCCESSFUL) { + dev_err(&pdev->dev, "Write of cache line size failed\n"); + rc = -EIO; + goto cleanup_nomem; + } + + /* Save away PCI config space for use following IOA reset */ + rc = pci_save_state(pdev, ioa_cfg->pci_cfg_buf); + + if (rc != PCIBIOS_SUCCESSFUL) { + dev_err(&pdev->dev, "Failed to save PCI config space\n"); + rc = -EIO; + goto cleanup_nomem; + } + + if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg))) + goto cleanup_nomem; + + if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg))) + goto cleanup_nomem; + + if ((rc = ipr_alloc_mem(ioa_cfg))) + goto cleanup; + + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); + rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg); + + if (rc) { + dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", + pdev->irq, rc); + goto cleanup_nolog; + } + + spin_lock(&ipr_driver_lock); + list_add_tail(&ioa_cfg->queue, &ipr_ioa_head); + spin_unlock(&ipr_driver_lock); + + LEAVE; + return 0; + +cleanup: + dev_err(&pdev->dev, "Couldn't allocate enough memory for device driver!\n"); +cleanup_nolog: + ipr_free_mem(ioa_cfg); +cleanup_nomem: + iounmap((void *) ipr_regs); + release_mem_region(ipr_regs_pci, pci_resource_len(pdev, 0)); + scsi_host_put(host); + + return rc; +} + +/** + * ipr_scan_vsets - Scans for VSET devices + * @ioa_cfg: ioa config struct + * + * Description: Since the VSET resources do not follow SAM in that we can have + * sparse LUNs with no LUN 0, we have to scan for these ourselves. + * + * Return value: + * none + **/ +static void ipr_scan_vsets(struct ipr_ioa_cfg *ioa_cfg) +{ + int target, lun; + + for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++) + for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ ) + scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun); +} + +/** + * ipr_initiate_ioa_bringdown - Bring down an adapter + * @ioa_cfg: ioa config struct + * @shutdown_type: shutdown type + * + * Description: This function will initiate bringing down the adapter. + * This consists of issuing an IOA shutdown to the adapter + * to flush the cache, and running BIST. + * If the caller needs to wait on the completion of the reset, + * the caller must sleep on the reset_wait_q. + * + * Return value: + * none + **/ +static void ipr_initiate_ioa_bringdown(struct ipr_ioa_cfg *ioa_cfg, + enum ipr_shutdown_type shutdown_type) +{ + ENTER; + if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) + ioa_cfg->sdt_state = ABORT_DUMP; + ioa_cfg->reset_retries = 0; + ioa_cfg->in_ioa_bringdown = 1; + ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); + LEAVE; +} + +/** + * __ipr_remove - Remove a single adapter + * @pdev: pci device struct + * + * Adapter hot plug remove entry point. + * + * Return value: + * none + **/ +static void __ipr_remove(struct pci_dev *pdev) +{ + unsigned long host_lock_flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + ENTER; + + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + + spin_lock(&ipr_driver_lock); + list_del(&ioa_cfg->queue); + spin_unlock(&ipr_driver_lock); + + if (ioa_cfg->sdt_state == ABORT_DUMP) + ioa_cfg->sdt_state = WAIT_FOR_DUMP; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + + ipr_free_all_resources(ioa_cfg); + + LEAVE; +} + +/** + * ipr_remove - IOA hot plug remove entry point + * @pdev: pci device struct + * + * Adapter hot plug remove entry point. + * + * Return value: + * none + **/ +static void ipr_remove(struct pci_dev *pdev) +{ + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + ENTER; + + ioa_cfg->allow_cmds = 0; + flush_scheduled_work(); + ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, + &ipr_trace_attr); + ipr_remove_dump_file(&ioa_cfg->host->shost_classdev.kobj, + &ipr_dump_attr); + scsi_remove_host(ioa_cfg->host); + + __ipr_remove(pdev); + + LEAVE; +} + +/** + * ipr_probe - Adapter hot plug add entry point + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int __devinit ipr_probe(struct pci_dev *pdev, + const struct pci_device_id *dev_id) +{ + struct ipr_ioa_cfg *ioa_cfg; + int rc; + + rc = ipr_probe_ioa(pdev, dev_id); + + if (rc) + return rc; + + ioa_cfg = pci_get_drvdata(pdev); + rc = ipr_probe_ioa_part2(ioa_cfg); + + if (rc) { + __ipr_remove(pdev); + return rc; + } + + rc = scsi_add_host(ioa_cfg->host, &pdev->dev); + + if (rc) { + __ipr_remove(pdev); + return rc; + } + + rc = ipr_create_trace_file(&ioa_cfg->host->shost_classdev.kobj, + &ipr_trace_attr); + + if (rc) { + scsi_remove_host(ioa_cfg->host); + __ipr_remove(pdev); + return rc; + } + + rc = ipr_create_dump_file(&ioa_cfg->host->shost_classdev.kobj, + &ipr_dump_attr); + + if (rc) { + ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, + &ipr_trace_attr); + scsi_remove_host(ioa_cfg->host); + __ipr_remove(pdev); + return rc; + } + + scsi_scan_host(ioa_cfg->host); + ipr_scan_vsets(ioa_cfg); + scsi_add_device(ioa_cfg->host, IPR_IOA_BUS, IPR_IOA_TARGET, IPR_IOA_LUN); + ioa_cfg->allow_ml_add_del = 1; + schedule_work(&ioa_cfg->work_q); + return 0; +} + +/** + * ipr_shutdown - Shutdown handler. + * @dev: device struct + * + * This function is invoked upon system shutdown/reboot. It will issue + * an adapter shutdown to the adapter to flush the write cache. + * + * Return value: + * none + **/ +static void ipr_shutdown(struct device *dev) +{ + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev)); + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); +} + +static struct pci_device_id ipr_pci_table[] __devinitdata = { + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, + 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + { } +}; +MODULE_DEVICE_TABLE(pci, ipr_pci_table); + +static struct pci_driver ipr_driver = { + .name = IPR_NAME, + .id_table = ipr_pci_table, + .probe = ipr_probe, + .remove = ipr_remove, + .driver = { + .shutdown = ipr_shutdown, + }, +}; + +/** + * ipr_init - Module entry point + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int __init ipr_init(void) +{ + ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", + IPR_DRIVER_VERSION, IPR_DRIVER_DATE); + + pci_register_driver(&ipr_driver); + + return 0; +} + +/** + * ipr_exit - Module unload + * + * Module unload entry point. + * + * Return value: + * none + **/ +static void __exit ipr_exit(void) +{ + pci_unregister_driver(&ipr_driver); +} + +module_init(ipr_init); +module_exit(ipr_exit); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h new file mode 100644 index 000000000..468c80796 --- /dev/null +++ b/drivers/scsi/ipr.h @@ -0,0 +1,1252 @@ +/* + * ipr.h -- driver for IBM Power Linux RAID adapters + * + * Written By: Brian King, IBM Corporation + * + * Copyright (C) 2003, 2004 IBM 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) 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 + * + */ + +#ifndef _IPR_H +#define _IPR_H + +#include +#include +#include +#include +#include +#ifdef CONFIG_KDB +#include +#endif + +/* + * Literals + */ +#define IPR_DRIVER_VERSION "2.0.7" +#define IPR_DRIVER_DATE "(May 21, 2004)" + +/* + * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing + * resulting in a bunch of extra debugging printks to the console + * + * IPR_DEBUG: Setting this to 1 will turn on some error path tracing. + * Enables the ipr_trace macro. + */ +#ifdef IPR_DEBUG_ALL +#define IPR_DEBUG 1 +#define IPR_DBG_TRACE 1 +#else +#define IPR_DEBUG 0 +#define IPR_DBG_TRACE 0 +#endif + +/* + * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding + * ops per device for devices not running tagged command queuing. + * This can be adjusted at runtime through sysfs device attributes. + */ +#define IPR_MAX_CMD_PER_LUN 6 + +/* + * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of + * ops the mid-layer can send to the adapter. + */ +#define IPR_NUM_BASE_CMD_BLKS 100 + +#define IPR_SUBS_DEV_ID_2780 0x0264 +#define IPR_SUBS_DEV_ID_5702 0x0266 +#define IPR_SUBS_DEV_ID_5703 0x0278 +#define IPR_SUBS_DEV_ID_572E 0x02D3 +#define IPR_SUBS_DEV_ID_573D 0x02D4 + +#define IPR_NAME "ipr" + +/* + * Return codes + */ +#define IPR_RC_JOB_CONTINUE 1 +#define IPR_RC_JOB_RETURN 2 + +/* + * IOASCs + */ +#define IPR_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 +#define IPR_IOASC_SYNC_REQUIRED 0x023f0000 +#define IPR_IOASC_MED_DO_NOT_REALLOC 0x03110C00 +#define IPR_IOASC_HW_SEL_TIMEOUT 0x04050000 +#define IPR_IOASC_HW_DEV_BUS_STATUS 0x04448500 +#define IPR_IOASC_IOASC_MASK 0xFFFFFF00 +#define IPR_IOASC_SCSI_STATUS_MASK 0x000000FF +#define IPR_IOASC_IR_RESOURCE_HANDLE 0x05250000 +#define IPR_IOASC_BUS_WAS_RESET 0x06290000 +#define IPR_IOASC_BUS_WAS_RESET_BY_OTHER 0x06298000 +#define IPR_IOASC_ABORTED_CMD_TERM_BY_HOST 0x0B5A0000 + +#define IPR_FIRST_DRIVER_IOASC 0x10000000 +#define IPR_IOASC_IOA_WAS_RESET 0x10000001 +#define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002 + +#define IPR_NUM_LOG_HCAMS 2 +#define IPR_NUM_CFG_CHG_HCAMS 2 +#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS) +#define IPR_MAX_NUM_TARGETS_PER_BUS 0x10 +#define IPR_MAX_NUM_LUNS_PER_TARGET 256 +#define IPR_MAX_NUM_VSET_LUNS_PER_TARGET 8 +#define IPR_VSET_BUS 0xff +#define IPR_IOA_BUS 0xff +#define IPR_IOA_TARGET 0xff +#define IPR_IOA_LUN 0xff +#define IPR_MAX_NUM_BUSES 4 +#define IPR_MAX_BUS_TO_SCAN IPR_MAX_NUM_BUSES + +#define IPR_NUM_RESET_RELOAD_RETRIES 3 + +/* We need resources for HCAMS, IOA reset, IOA bringdown, and ERP */ +#define IPR_NUM_INTERNAL_CMD_BLKS (IPR_NUM_HCAMS + \ + ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 3) + +#define IPR_MAX_COMMANDS IPR_NUM_BASE_CMD_BLKS +#define IPR_NUM_CMD_BLKS (IPR_NUM_BASE_CMD_BLKS + \ + IPR_NUM_INTERNAL_CMD_BLKS) + +#define IPR_MAX_PHYSICAL_DEVS 192 + +#define IPR_MAX_SGLIST 64 +#define IPR_MAX_SECTORS 512 +#define IPR_MAX_CDB_LEN 16 + +#define IPR_DEFAULT_BUS_WIDTH 16 +#define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) +#define IPR_U160_SCSI_RATE ((160 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) +#define IPR_U320_SCSI_RATE ((320 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) +#define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8)) + +#define IPR_IOA_RES_HANDLE 0xffffffff +#define IPR_IOA_RES_ADDR 0x00ffffff + +/* + * Adapter Commands + */ +#define IPR_RESET_DEVICE 0xC3 +#define IPR_RESET_TYPE_SELECT 0x80 +#define IPR_LUN_RESET 0x40 +#define IPR_TARGET_RESET 0x20 +#define IPR_BUS_RESET 0x10 +#define IPR_ID_HOST_RR_Q 0xC4 +#define IPR_QUERY_IOA_CONFIG 0xC5 +#define IPR_ABORT_TASK 0xC7 +#define IPR_CANCEL_ALL_REQUESTS 0xCE +#define IPR_HOST_CONTROLLED_ASYNC 0xCF +#define IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE 0x01 +#define IPR_HCAM_CDB_OP_CODE_LOG_DATA 0x02 +#define IPR_SET_SUPPORTED_DEVICES 0xFB +#define IPR_IOA_SHUTDOWN 0xF7 +#define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05 + +/* + * Timeouts + */ +#define IPR_SHUTDOWN_TIMEOUT (10 * 60 * HZ) +#define IPR_VSET_RW_TIMEOUT (2 * 60 * HZ) +#define IPR_ABBREV_SHUTDOWN_TIMEOUT (10 * HZ) +#define IPR_DEVICE_RESET_TIMEOUT (30 * HZ) +#define IPR_CANCEL_ALL_TIMEOUT (30 * HZ) +#define IPR_ABORT_TASK_TIMEOUT (30 * HZ) +#define IPR_INTERNAL_TIMEOUT (30 * HZ) +#define IPR_WRITE_BUFFER_TIMEOUT (10 * 60 * HZ) +#define IPR_SET_SUP_DEVICE_TIMEOUT (2 * 60 * HZ) +#define IPR_REQUEST_SENSE_TIMEOUT (10 * HZ) +#define IPR_OPERATIONAL_TIMEOUT (5 * 60 * HZ) +#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ) +#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) +#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) +#define IPR_DUMP_TIMEOUT (15 * HZ) + +/* + * SCSI Literals + */ +#define IPR_VENDOR_ID_LEN 8 +#define IPR_PROD_ID_LEN 16 +#define IPR_SERIAL_NUM_LEN 8 + +/* + * Hardware literals + */ +#define IPR_FMT2_MBX_ADDR_MASK 0x0fffffff +#define IPR_FMT2_MBX_BAR_SEL_MASK 0xf0000000 +#define IPR_FMT2_MKR_BAR_SEL_SHIFT 28 +#define IPR_GET_FMT2_BAR_SEL(mbx) \ +(((mbx) & IPR_FMT2_MBX_BAR_SEL_MASK) >> IPR_FMT2_MKR_BAR_SEL_SHIFT) +#define IPR_SDT_FMT2_BAR0_SEL 0x0 +#define IPR_SDT_FMT2_BAR1_SEL 0x1 +#define IPR_SDT_FMT2_BAR2_SEL 0x2 +#define IPR_SDT_FMT2_BAR3_SEL 0x3 +#define IPR_SDT_FMT2_BAR4_SEL 0x4 +#define IPR_SDT_FMT2_BAR5_SEL 0x5 +#define IPR_SDT_FMT2_EXP_ROM_SEL 0x8 +#define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 +#define IPR_DOORBELL 0x82800000 + +#define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0) +#define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3) +#define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4) +#define IPR_PCII_NO_HOST_RRQ (0x80000000 >> 5) +#define IPR_PCII_CRITICAL_OPERATION (0x80000000 >> 6) +#define IPR_PCII_IO_DEBUG_ACKNOWLEDGE (0x80000000 >> 7) +#define IPR_PCII_IOARRIN_LOST (0x80000000 >> 27) +#define IPR_PCII_MMIO_ERROR (0x80000000 >> 28) +#define IPR_PCII_PROC_ERR_STATE (0x80000000 >> 29) +#define IPR_PCII_HRRQ_UPDATED (0x80000000 >> 30) +#define IPR_PCII_CORE_ISSUED_RST_REQ (0x80000000 >> 31) + +#define IPR_PCII_ERROR_INTERRUPTS \ +(IPR_PCII_IOARCB_XFER_FAILED | IPR_PCII_IOA_UNIT_CHECKED | \ +IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR) + +#define IPR_PCII_OPER_INTERRUPTS \ +(IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED | IPR_PCII_IOA_TRANS_TO_OPER) + +#define IPR_UPROCI_RESET_ALERT (0x80000000 >> 7) +#define IPR_UPROCI_IO_DEBUG_ALERT (0x80000000 >> 9) + +#define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC 200000 /* 200 ms */ +#define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC 200000 /* 200 ms */ + +/* + * Dump literals + */ +#define IPR_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) +#define IPR_NUM_SDT_ENTRIES 511 +#define IPR_MAX_NUM_DUMP_PAGES ((IPR_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) + +/* + * Misc literals + */ +#define IPR_NUM_IOADL_ENTRIES IPR_MAX_SGLIST + +/* + * Adapter interface types + */ + +struct ipr_res_addr { + u8 reserved; + u8 bus; + u8 target; + u8 lun; +#define IPR_GET_PHYS_LOC(res_addr) \ + (((res_addr).bus << 16) | ((res_addr).target << 8) | (res_addr).lun) +}__attribute__((packed, aligned (4))); + +struct ipr_std_inq_vpids { + u8 vendor_id[IPR_VENDOR_ID_LEN]; + u8 product_id[IPR_PROD_ID_LEN]; +}__attribute__((packed)); + +struct ipr_std_inq_data { + u8 peri_qual_dev_type; +#define IPR_STD_INQ_PERI_QUAL(peri) ((peri) >> 5) +#define IPR_STD_INQ_PERI_DEV_TYPE(peri) ((peri) & 0x1F) + + u8 removeable_medium_rsvd; +#define IPR_STD_INQ_REMOVEABLE_MEDIUM 0x80 + +#define IPR_IS_DASD_DEVICE(std_inq) \ +((IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_DISK) && \ +!(((std_inq).removeable_medium_rsvd) & IPR_STD_INQ_REMOVEABLE_MEDIUM)) + +#define IPR_IS_SES_DEVICE(std_inq) \ +(IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_ENCLOSURE) + + u8 version; + u8 aen_naca_fmt; + u8 additional_len; + u8 sccs_rsvd; + u8 bq_enc_multi; + u8 sync_cmdq_flags; + + struct ipr_std_inq_vpids vpids; + + u8 ros_rsvd_ram_rsvd[4]; + + u8 serial_num[IPR_SERIAL_NUM_LEN]; +}__attribute__ ((packed)); + +struct ipr_config_table_entry { + u8 service_level; + u8 array_id; + u8 flags; +#define IPR_IS_IOA_RESOURCE 0x80 +#define IPR_IS_ARRAY_MEMBER 0x20 +#define IPR_IS_HOT_SPARE 0x10 + + u8 rsvd_subtype; +#define IPR_RES_SUBTYPE(res) (((res)->cfgte.rsvd_subtype) & 0x0f) +#define IPR_SUBTYPE_AF_DASD 0 +#define IPR_SUBTYPE_GENERIC_SCSI 1 +#define IPR_SUBTYPE_VOLUME_SET 2 + + struct ipr_res_addr res_addr; + u32 res_handle; + u32 reserved4[2]; + struct ipr_std_inq_data std_inq_data; +}__attribute__ ((packed, aligned (4))); + +struct ipr_config_table_hdr { + u8 num_entries; + u8 flags; +#define IPR_UCODE_DOWNLOAD_REQ 0x10 + u16 reserved; +}__attribute__((packed, aligned (4))); + +struct ipr_config_table { + struct ipr_config_table_hdr hdr; + struct ipr_config_table_entry dev[IPR_MAX_PHYSICAL_DEVS]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_cfg_ch_not { + struct ipr_config_table_entry cfgte; + u8 reserved[936]; +}__attribute__((packed, aligned (4))); + +struct ipr_supported_device { + u16 data_length; + u8 reserved; + u8 num_records; + struct ipr_std_inq_vpids vpids; + u8 reserved2[16]; +}__attribute__((packed, aligned (4))); + +/* Command packet structure */ +struct ipr_cmd_pkt { + u16 reserved; /* Reserved by IOA */ + u8 request_type; +#define IPR_RQTYPE_SCSICDB 0x00 +#define IPR_RQTYPE_IOACMD 0x01 +#define IPR_RQTYPE_HCAM 0x02 + + u8 luntar_luntrn; + + u8 flags_hi; +#define IPR_FLAGS_HI_WRITE_NOT_READ 0x80 +#define IPR_FLAGS_HI_NO_ULEN_CHK 0x20 +#define IPR_FLAGS_HI_SYNC_OVERRIDE 0x10 +#define IPR_FLAGS_HI_SYNC_COMPLETE 0x08 +#define IPR_FLAGS_HI_NO_LINK_DESC 0x04 + + u8 flags_lo; +#define IPR_FLAGS_LO_ALIGNED_BFR 0x20 +#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 +#define IPR_FLAGS_LO_UNTAGGED_TASK 0x00 +#define IPR_FLAGS_LO_SIMPLE_TASK 0x02 +#define IPR_FLAGS_LO_ORDERED_TASK 0x04 +#define IPR_FLAGS_LO_HEAD_OF_Q_TASK 0x06 +#define IPR_FLAGS_LO_ACA_TASK 0x08 + + u8 cdb[16]; + u16 timeout; +}__attribute__ ((packed, aligned(4))); + +/* IOA Request Control Block 128 bytes */ +struct ipr_ioarcb { + u32 ioarcb_host_pci_addr; + u32 reserved; + u32 res_handle; + u32 host_response_handle; + u32 reserved1; + u32 reserved2; + u32 reserved3; + + u32 write_data_transfer_length; + u32 read_data_transfer_length; + u32 write_ioadl_addr; + u32 write_ioadl_len; + u32 read_ioadl_addr; + u32 read_ioadl_len; + + u32 ioasa_host_pci_addr; + u16 ioasa_len; + u16 reserved4; + + struct ipr_cmd_pkt cmd_pkt; + + u32 add_cmd_parms_len; + u32 add_cmd_parms[10]; +}__attribute__((packed, aligned (4))); + +struct ipr_ioadl_desc { + u32 flags_and_data_len; +#define IPR_IOADL_FLAGS_MASK 0xff000000 +#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK) +#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff +#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK) +#define IPR_IOADL_FLAGS_READ 0x48000000 +#define IPR_IOADL_FLAGS_READ_LAST 0x49000000 +#define IPR_IOADL_FLAGS_WRITE 0x68000000 +#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000 +#define IPR_IOADL_FLAGS_LAST 0x01000000 + + u32 address; +}__attribute__((packed, aligned (8))); + +struct ipr_ioasa_vset { + u32 failing_lba_hi; + u32 failing_lba_lo; + u32 ioa_data[22]; +}__attribute__((packed, aligned (4))); + +struct ipr_ioasa_af_dasd { + u32 failing_lba; +}__attribute__((packed, aligned (4))); + +struct ipr_ioasa_gpdd { + u8 end_state; + u8 bus_phase; + u16 reserved; + u32 ioa_data[23]; +}__attribute__((packed, aligned (4))); + +struct ipr_ioasa_raw { + u32 ioa_data[24]; +}__attribute__((packed, aligned (4))); + +struct ipr_ioasa { + u32 ioasc; +#define IPR_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24) +#define IPR_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16) +#define IPR_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8) +#define IPR_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff) + + u16 ret_stat_len; /* Length of the returned IOASA */ + + u16 avail_stat_len; /* Total Length of status available. */ + + u32 residual_data_len; /* number of bytes in the host data */ + /* buffers that were not used by the IOARCB command. */ + + u32 ilid; +#define IPR_NO_ILID 0 +#define IPR_DRIVER_ILID 0xffffffff + + u32 fd_ioasc; + + u32 fd_phys_locator; + + u32 fd_res_handle; + + u32 ioasc_specific; /* status code specific field */ +#define IPR_IOASC_SPECIFIC_MASK 0x00ffffff +#define IPR_FIELD_POINTER_VALID (0x80000000 >> 8) +#define IPR_FIELD_POINTER_MASK 0x0000ffff + + union { + struct ipr_ioasa_vset vset; + struct ipr_ioasa_af_dasd dasd; + struct ipr_ioasa_gpdd gpdd; + struct ipr_ioasa_raw raw; + } u; +}__attribute__((packed, aligned (4))); + +struct ipr_mode_parm_hdr { + u8 length; + u8 medium_type; + u8 device_spec_parms; + u8 block_desc_len; +}__attribute__((packed)); + +struct ipr_mode_pages { + struct ipr_mode_parm_hdr hdr; + u8 data[255 - sizeof(struct ipr_mode_parm_hdr)]; +}__attribute__((packed)); + +struct ipr_mode_page_hdr { + u8 ps_page_code; +#define IPR_MODE_PAGE_PS 0x80 +#define IPR_GET_MODE_PAGE_CODE(hdr) ((hdr)->ps_page_code & 0x3F) + u8 page_length; +}__attribute__ ((packed)); + +struct ipr_dev_bus_entry { + struct ipr_res_addr res_addr; + u8 flags; +#define IPR_SCSI_ATTR_ENABLE_QAS 0x80 +#define IPR_SCSI_ATTR_DISABLE_QAS 0x40 +#define IPR_SCSI_ATTR_QAS_MASK 0xC0 +#define IPR_SCSI_ATTR_ENABLE_TM 0x20 +#define IPR_SCSI_ATTR_NO_TERM_PWR 0x10 +#define IPR_SCSI_ATTR_TM_SUPPORTED 0x08 +#define IPR_SCSI_ATTR_LVD_TO_SE_NOT_ALLOWED 0x04 + + u8 scsi_id; + u8 bus_width; + u8 extended_reset_delay; +#define IPR_EXTENDED_RESET_DELAY 7 + + u32 max_xfer_rate; + + u8 spinup_delay; + u8 reserved3; + u16 reserved4; +}__attribute__((packed, aligned (4))); + +struct ipr_mode_page28 { + struct ipr_mode_page_hdr hdr; + u8 num_entries; + u8 entry_length; + struct ipr_dev_bus_entry bus[0]; +}__attribute__((packed)); + +struct ipr_ioa_vpd { + struct ipr_std_inq_data std_inq_data; + u8 ascii_part_num[12]; + u8 reserved[40]; + u8 ascii_plant_code[4]; +}__attribute__((packed)); + +struct ipr_inquiry_page3 { + u8 peri_qual_dev_type; + u8 page_code; + u8 reserved1; + u8 page_length; + u8 ascii_len; + u8 reserved2[3]; + u8 load_id[4]; + u8 major_release; + u8 card_type; + u8 minor_release[2]; + u8 ptf_number[4]; + u8 patch_number[4]; +}__attribute__((packed)); + +struct ipr_hostrcb_device_data_entry { + struct ipr_std_inq_vpids dev_vpids; + u8 dev_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_res_addr dev_res_addr; + struct ipr_std_inq_vpids new_dev_vpids; + u8 new_dev_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids ioa_last_with_dev_vpids; + u8 ioa_last_with_dev_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids cfc_last_with_dev_vpids; + u8 cfc_last_with_dev_sn[IPR_SERIAL_NUM_LEN]; + u32 ioa_data[5]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_array_data_entry { + struct ipr_std_inq_vpids vpids; + u8 serial_num[IPR_SERIAL_NUM_LEN]; + struct ipr_res_addr expected_dev_res_addr; + struct ipr_res_addr dev_res_addr; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_type_ff_error { + u32 ioa_data[246]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_type_01_error { + u32 seek_counter; + u32 read_counter; + u8 sense_data[32]; + u32 ioa_data[236]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_type_02_error { + struct ipr_std_inq_vpids ioa_vpids; + u8 ioa_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids cfc_vpids; + u8 cfc_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids ioa_last_attached_to_cfc_vpids; + u8 ioa_last_attached_to_cfc_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids cfc_last_attached_to_ioa_vpids; + u8 cfc_last_attached_to_ioa_sn[IPR_SERIAL_NUM_LEN]; + u32 ioa_data[3]; + u8 reserved[844]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_type_03_error { + struct ipr_std_inq_vpids ioa_vpids; + u8 ioa_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids cfc_vpids; + u8 cfc_sn[IPR_SERIAL_NUM_LEN]; + u32 errors_detected; + u32 errors_logged; + u8 ioa_data[12]; + struct ipr_hostrcb_device_data_entry dev_entry[3]; + u8 reserved[444]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_type_04_error { + struct ipr_std_inq_vpids ioa_vpids; + u8 ioa_sn[IPR_SERIAL_NUM_LEN]; + struct ipr_std_inq_vpids cfc_vpids; + u8 cfc_sn[IPR_SERIAL_NUM_LEN]; + u8 ioa_data[12]; + struct ipr_hostrcb_array_data_entry array_member[10]; + u32 exposed_mode_adn; + u32 array_id; + struct ipr_std_inq_vpids incomp_dev_vpids; + u8 incomp_dev_sn[IPR_SERIAL_NUM_LEN]; + u32 ioa_data2; + struct ipr_hostrcb_array_data_entry array_member2[8]; + struct ipr_res_addr last_func_vset_res_addr; + u8 vset_serial_num[IPR_SERIAL_NUM_LEN]; + u8 protection_level[8]; + u8 reserved[124]; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_error { + u32 failing_dev_ioasc; + struct ipr_res_addr failing_dev_res_addr; + u32 failing_dev_res_handle; + u32 prc; + union { + struct ipr_hostrcb_type_ff_error type_ff_error; + struct ipr_hostrcb_type_01_error type_01_error; + struct ipr_hostrcb_type_02_error type_02_error; + struct ipr_hostrcb_type_03_error type_03_error; + struct ipr_hostrcb_type_04_error type_04_error; + } u; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb_raw { + u32 data[sizeof(struct ipr_hostrcb_error)/sizeof(u32)]; +}__attribute__((packed, aligned (4))); + +struct ipr_hcam { + u8 op_code; +#define IPR_HOST_RCB_OP_CODE_CONFIG_CHANGE 0xE1 +#define IPR_HOST_RCB_OP_CODE_LOG_DATA 0xE2 + + u8 notify_type; +#define IPR_HOST_RCB_NOTIF_TYPE_EXISTING_CHANGED 0x00 +#define IPR_HOST_RCB_NOTIF_TYPE_NEW_ENTRY 0x01 +#define IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY 0x02 +#define IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY 0x10 +#define IPR_HOST_RCB_NOTIF_TYPE_INFORMATION_ENTRY 0x11 + + u8 notifications_lost; +#define IPR_HOST_RCB_NO_NOTIFICATIONS_LOST 0 +#define IPR_HOST_RCB_NOTIFICATIONS_LOST 0x80 + + u8 flags; +#define IPR_HOSTRCB_INTERNAL_OPER 0x80 +#define IPR_HOSTRCB_ERR_RESP_SENT 0x40 + + u8 overlay_id; +#define IPR_HOST_RCB_OVERLAY_ID_1 0x01 +#define IPR_HOST_RCB_OVERLAY_ID_2 0x02 +#define IPR_HOST_RCB_OVERLAY_ID_3 0x03 +#define IPR_HOST_RCB_OVERLAY_ID_4 0x04 +#define IPR_HOST_RCB_OVERLAY_ID_6 0x06 +#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT 0xFF + + u8 reserved1[3]; + u32 ilid; + u32 time_since_last_ioa_reset; + u32 reserved2; + u32 length; + + union { + struct ipr_hostrcb_error error; + struct ipr_hostrcb_cfg_ch_not ccn; + struct ipr_hostrcb_raw raw; + } u; +}__attribute__((packed, aligned (4))); + +struct ipr_hostrcb { + struct ipr_hcam hcam; + u32 hostrcb_dma; + struct list_head queue; +}; + +/* IPR smart dump table structures */ +struct ipr_sdt_entry { + u32 bar_str_offset; + u32 end_offset; + u8 entry_byte; + u8 reserved[3]; + + u8 flags; +#define IPR_SDT_ENDIAN 0x80 +#define IPR_SDT_VALID_ENTRY 0x20 + + u8 resv; + u16 priority; +}__attribute__((packed, aligned (4))); + +struct ipr_sdt_header { + u32 state; + u32 num_entries; + u32 num_entries_used; + u32 dump_size; +}__attribute__((packed, aligned (4))); + +struct ipr_sdt { + struct ipr_sdt_header hdr; + struct ipr_sdt_entry entry[IPR_NUM_SDT_ENTRIES]; +}__attribute__((packed, aligned (4))); + +struct ipr_uc_sdt { + struct ipr_sdt_header hdr; + struct ipr_sdt_entry entry[1]; +}__attribute__((packed, aligned (4))); + +/* + * Driver types + */ +struct ipr_bus_attributes { + u8 bus; + u8 qas_enabled; + u8 bus_width; + u8 reserved; + u32 max_xfer_rate; +}; + +struct ipr_resource_entry { + struct ipr_config_table_entry cfgte; + u8 needs_sync_complete:1; + u8 in_erp:1; + u8 add_to_ml:1; + u8 del_from_ml:1; + u8 resetting_device:1; + u8 tcq_active:1; + + int qdepth; + struct scsi_device *sdev; + struct list_head queue; +}; + +struct ipr_resource_hdr { + u16 num_entries; + u16 reserved; +}; + +struct ipr_resource_table { + struct ipr_resource_hdr hdr; + struct ipr_resource_entry dev[IPR_MAX_PHYSICAL_DEVS]; +}; + +struct ipr_misc_cbs { + struct ipr_ioa_vpd ioa_vpd; + struct ipr_inquiry_page3 page3_data; + struct ipr_mode_pages mode_pages; + struct ipr_supported_device supp_dev; +}; + +struct ipr_interrupts { + unsigned long set_interrupt_mask_reg; + unsigned long clr_interrupt_mask_reg; + unsigned long sense_interrupt_mask_reg; + unsigned long clr_interrupt_reg; + + unsigned long sense_interrupt_reg; + unsigned long ioarrin_reg; + unsigned long sense_uproc_interrupt_reg; + unsigned long set_uproc_interrupt_reg; + unsigned long clr_uproc_interrupt_reg; +}; + +struct ipr_chip_cfg_t { + u32 mailbox; + u8 cache_line_size; + struct ipr_interrupts regs; +}; + +enum ipr_shutdown_type { + IPR_SHUTDOWN_NORMAL = 0x00, + IPR_SHUTDOWN_PREPARE_FOR_NORMAL = 0x40, + IPR_SHUTDOWN_ABBREV = 0x80, + IPR_SHUTDOWN_NONE = 0x100 +}; + +struct ipr_trace_entry { + u32 time; + + u8 op_code; + u8 type; +#define IPR_TRACE_START 0x00 +#define IPR_TRACE_FINISH 0xff + u16 cmd_index; + + u32 res_handle; + union { + u32 ioasc; + u32 add_data; + u32 res_addr; + } u; +}; + +struct ipr_sglist { + u32 order; + u32 num_sg; + u32 buffer_len; + struct scatterlist scatterlist[1]; +}; + +enum ipr_sdt_state { + INACTIVE, + WAIT_FOR_DUMP, + GET_DUMP, + ABORT_DUMP, + DUMP_OBTAINED +}; + +/* Per-controller data */ +struct ipr_ioa_cfg { + char eye_catcher[8]; +#define IPR_EYECATCHER "iprcfg" + + struct list_head queue; + + u8 allow_interrupts:1; + u8 in_reset_reload:1; + u8 in_ioa_bringdown:1; + u8 ioa_unit_checked:1; + u8 ioa_is_dead:1; + u8 dump_taken:1; + u8 allow_cmds:1; + u8 allow_ml_add_del:1; + + u16 type; /* CCIN of the card */ + + u8 log_level; +#define IPR_MAX_LOG_LEVEL 4 +#define IPR_DEFAULT_LOG_LEVEL 2 + +#define IPR_NUM_TRACE_INDEX_BITS 8 +#define IPR_NUM_TRACE_ENTRIES (1 << IPR_NUM_TRACE_INDEX_BITS) +#define IPR_TRACE_SIZE (sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES) + char trace_start[8]; +#define IPR_TRACE_START_LABEL "trace" + struct ipr_trace_entry *trace; + u32 trace_index:IPR_NUM_TRACE_INDEX_BITS; + + /* + * Queue for free command blocks + */ + char ipr_free_label[8]; +#define IPR_FREEQ_LABEL "free-q" + struct list_head free_q; + + /* + * Queue for command blocks outstanding to the adapter + */ + char ipr_pending_label[8]; +#define IPR_PENDQ_LABEL "pend-q" + struct list_head pending_q; + + char cfg_table_start[8]; +#define IPR_CFG_TBL_START "cfg" + struct ipr_config_table *cfg_table; + u32 cfg_table_dma; + + char resource_table_label[8]; +#define IPR_RES_TABLE_LABEL "res_tbl" + struct ipr_resource_entry *res_entries; + struct list_head free_res_q; + struct list_head used_res_q; + + char ipr_hcam_label[8]; +#define IPR_HCAM_LABEL "hcams" + struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS]; + u32 hostrcb_dma[IPR_NUM_HCAMS]; + struct list_head hostrcb_free_q; + struct list_head hostrcb_pending_q; + + u32 *host_rrq; + u32 host_rrq_dma; +#define IPR_HRRQ_REQ_RESP_HANDLE_MASK 0xfffffffc +#define IPR_HRRQ_RESP_BIT_SET 0x00000002 +#define IPR_HRRQ_TOGGLE_BIT 0x00000001 +#define IPR_HRRQ_REQ_RESP_HANDLE_SHIFT 2 + volatile u32 *hrrq_start; + volatile u32 *hrrq_end; + volatile u32 *hrrq_curr; + volatile u32 toggle_bit; + + struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES]; + + const struct ipr_chip_cfg_t *chip_cfg; + + unsigned long hdw_dma_regs; /* iomapped PCI memory space */ + unsigned long hdw_dma_regs_pci; /* raw PCI memory space */ + unsigned long ioa_mailbox; + struct ipr_interrupts regs; + + u32 pci_cfg_buf[64]; + u16 saved_pcix_cmd_reg; + u16 reset_retries; + + u32 errors_logged; + + struct Scsi_Host *host; + struct pci_dev *pdev; + struct ipr_sglist *ucode_sglist; + struct ipr_mode_pages *saved_mode_pages; + u8 saved_mode_page_len; + + struct work_struct work_q; + + wait_queue_head_t reset_wait_q; + + struct ipr_dump *dump; + enum ipr_sdt_state sdt_state; + + struct ipr_misc_cbs *vpd_cbs; + u32 vpd_cbs_dma; + + struct pci_pool *ipr_cmd_pool; + + struct ipr_cmnd *reset_cmd; + + char ipr_cmd_label[8]; +#define IPR_CMD_LABEL "ipr_cmnd" + struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS]; + u32 ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS]; +}; + +struct ipr_cmnd { + struct ipr_ioarcb ioarcb; + struct ipr_ioasa ioasa; + struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES]; + struct list_head queue; + struct scsi_cmnd *scsi_cmd; + struct completion completion; + struct timer_list timer; + void (*done) (struct ipr_cmnd *); + int (*job_step) (struct ipr_cmnd *); + u16 cmd_index; + u8 sense_buffer[SCSI_SENSE_BUFFERSIZE]; + dma_addr_t sense_buffer_dma; + unsigned short dma_use_sg; + dma_addr_t dma_handle; + union { + enum ipr_shutdown_type shutdown_type; + struct ipr_hostrcb *hostrcb; + unsigned long time_left; + unsigned long scratch; + struct ipr_resource_entry *res; + struct ipr_cmnd *sibling; + struct scsi_device *sdev; + } u; + + struct ipr_ioa_cfg *ioa_cfg; +}; + +struct ipr_ses_table_entry { + char product_id[17]; + char compare_product_id_byte[17]; + u32 max_bus_speed_limit; /* MB/sec limit for this backplane */ +}; + +struct ipr_dump_header { + u32 eye_catcher; +#define IPR_DUMP_EYE_CATCHER 0xC5D4E3F2 + u32 len; + u32 num_entries; + u32 first_entry_offset; + u32 status; +#define IPR_DUMP_STATUS_SUCCESS 0 +#define IPR_DUMP_STATUS_QUAL_SUCCESS 2 +#define IPR_DUMP_STATUS_FAILED 0xffffffff + u32 os; +#define IPR_DUMP_OS_LINUX 0x4C4E5558 + u32 driver_name; +#define IPR_DUMP_DRIVER_NAME 0x49505232 +}__attribute__((packed, aligned (4))); + +struct ipr_dump_entry_header { + u32 eye_catcher; +#define IPR_DUMP_EYE_CATCHER 0xC5D4E3F2 + u32 len; + u32 num_elems; + u32 offset; + u32 data_type; +#define IPR_DUMP_DATA_TYPE_ASCII 0x41534349 +#define IPR_DUMP_DATA_TYPE_BINARY 0x42494E41 + u32 id; +#define IPR_DUMP_IOA_DUMP_ID 0x494F4131 +#define IPR_DUMP_LOCATION_ID 0x4C4F4341 +#define IPR_DUMP_TRACE_ID 0x54524143 +#define IPR_DUMP_DRIVER_VERSION_ID 0x44525652 +#define IPR_DUMP_DRIVER_TYPE_ID 0x54595045 +#define IPR_DUMP_IOA_CTRL_BLK 0x494F4342 +#define IPR_DUMP_PEND_OPS 0x414F5053 + u32 status; +}__attribute__((packed, aligned (4))); + +struct ipr_dump_location_entry { + struct ipr_dump_entry_header hdr; + u8 location[BUS_ID_SIZE]; +}__attribute__((packed)); + +struct ipr_dump_trace_entry { + struct ipr_dump_entry_header hdr; + u32 trace[IPR_TRACE_SIZE / sizeof(u32)]; +}__attribute__((packed, aligned (4))); + +struct ipr_dump_version_entry { + struct ipr_dump_entry_header hdr; + u8 version[sizeof(IPR_DRIVER_VERSION)]; +}; + +struct ipr_dump_ioa_type_entry { + struct ipr_dump_entry_header hdr; + u32 type; + u32 fw_version; +}; + +struct ipr_driver_dump { + struct ipr_dump_header hdr; + struct ipr_dump_version_entry version_entry; + struct ipr_dump_location_entry location_entry; + struct ipr_dump_ioa_type_entry ioa_type_entry; + struct ipr_dump_trace_entry trace_entry; +}__attribute__((packed)); + +struct ipr_ioa_dump { + struct ipr_dump_entry_header hdr; + struct ipr_sdt sdt; + u32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES]; + u32 reserved; + u32 next_page_index; + u32 page_offset; + u32 format; +#define IPR_SDT_FMT2 2 +#define IPR_SDT_UNKNOWN 3 +}__attribute__((packed, aligned (4))); + +struct ipr_dump { + struct kobject kobj; + struct ipr_ioa_cfg *ioa_cfg; + struct ipr_driver_dump driver_dump; + struct ipr_ioa_dump ioa_dump; +}; + +struct ipr_error_table_t { + u32 ioasc; + int log_ioasa; + int log_hcam; + char *error; +}; + +struct ipr_software_inq_lid_info { + u32 load_id; + u32 timestamp[3]; +}__attribute__((packed, aligned (4))); + +struct ipr_ucode_image_header { + u32 header_length; + u32 lid_table_offset; + u8 major_release; + u8 card_type; + u8 minor_release[2]; + u8 reserved[20]; + char eyecatcher[16]; + u32 num_lids; + struct ipr_software_inq_lid_info lid[1]; +}__attribute__((packed, aligned (4))); + +/* + * Macros + */ +#if IPR_DEBUG +#define IPR_DBG_CMD(CMD) do { CMD; } while (0) +#else +#define IPR_DBG_CMD(CMD) +#endif + +#define ipr_breakpoint_data KERN_ERR IPR_NAME\ +": %s: %s: Line: %d ioa_cfg: %p\n", __FILE__, \ +__FUNCTION__, __LINE__, ioa_cfg + +#if defined(CONFIG_KDB) && !defined(CONFIG_PPC_ISERIES) +#define ipr_breakpoint {printk(ipr_breakpoint_data); KDB_ENTER();} +#define ipr_breakpoint_or_die {printk(ipr_breakpoint_data); KDB_ENTER();} +#else +#define ipr_breakpoint +#define ipr_breakpoint_or_die panic(ipr_breakpoint_data) +#endif + +#ifdef CONFIG_SCSI_IPR_TRACE +#define ipr_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) +#define ipr_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) +#else +#define ipr_create_trace_file(kobj, attr) 0 +#define ipr_remove_trace_file(kobj, attr) do { } while(0) +#endif + +#ifdef CONFIG_SCSI_IPR_DUMP +#define ipr_create_dump_file(kobj, attr) sysfs_create_bin_file(kobj, attr) +#define ipr_remove_dump_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) +#else +#define ipr_create_dump_file(kobj, attr) 0 +#define ipr_remove_dump_file(kobj, attr) do { } while(0) +#endif + +/* + * Error logging macros + */ +#define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__) +#define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__) +#define ipr_crit(...) printk(KERN_CRIT IPR_NAME ": "__VA_ARGS__) +#define ipr_warn(...) printk(KERN_WARNING IPR_NAME": "__VA_ARGS__) +#define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)) + +#define ipr_sdev_printk(level, sdev, fmt, ...) \ + printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, sdev->host->host_no, \ + sdev->channel, sdev->id, sdev->lun, ##__VA_ARGS__) + +#define ipr_sdev_err(sdev, fmt, ...) \ + ipr_sdev_printk(KERN_ERR, sdev, fmt, ##__VA_ARGS__) + +#define ipr_sdev_info(sdev, fmt, ...) \ + ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__) + +#define ipr_sdev_dbg(sdev, fmt, ...) \ + IPR_DBG_CMD(ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__)) + +#define ipr_res_printk(level, ioa_cfg, res, fmt, ...) \ + printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, ioa_cfg->host->host_no, \ + res.bus, res.target, res.lun, ##__VA_ARGS__) + +#define ipr_res_err(ioa_cfg, res, fmt, ...) \ + ipr_res_printk(KERN_ERR, ioa_cfg, res, fmt, ##__VA_ARGS__) +#define ipr_res_dbg(ioa_cfg, res, fmt, ...) \ + IPR_DBG_CMD(ipr_res_printk(KERN_INFO, ioa_cfg, res, fmt, ##__VA_ARGS__)) + +#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\ + __FILE__, __FUNCTION__, __LINE__) + +#if IPR_DBG_TRACE +#define ENTER printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__) +#define LEAVE printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__) +#else +#define ENTER +#define LEAVE +#endif + +#define ipr_err_separator \ +ipr_err("----------------------------------------------------------\n") + + +/* + * Inlines + */ + +/** + * ipr_is_ioa_resource - Determine if a resource is the IOA + * @res: resource entry struct + * + * Return value: + * 1 if IOA / 0 if not IOA + **/ +static inline int ipr_is_ioa_resource(struct ipr_resource_entry *res) +{ + return (res->cfgte.flags & IPR_IS_IOA_RESOURCE) ? 1 : 0; +} + +/** + * ipr_is_af_dasd_device - Determine if a resource is an AF DASD + * @res: resource entry struct + * + * Return value: + * 1 if AF DASD / 0 if not AF DASD + **/ +static inline int ipr_is_af_dasd_device(struct ipr_resource_entry *res) +{ + if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) && + !ipr_is_ioa_resource(res) && + IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_AF_DASD) + return 1; + else + return 0; +} + +/** + * ipr_is_vset_device - Determine if a resource is a VSET + * @res: resource entry struct + * + * Return value: + * 1 if VSET / 0 if not VSET + **/ +static inline int ipr_is_vset_device(struct ipr_resource_entry *res) +{ + if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) && + !ipr_is_ioa_resource(res) && + IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_VOLUME_SET) + return 1; + else + return 0; +} + +/** + * ipr_is_gscsi - Determine if a resource is a generic scsi resource + * @res: resource entry struct + * + * Return value: + * 1 if GSCSI / 0 if not GSCSI + **/ +static inline int ipr_is_gscsi(struct ipr_resource_entry *res) +{ + if (!ipr_is_ioa_resource(res) && + IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_SCSI) + return 1; + else + return 0; +} + +/** + * ipr_is_device - Determine if resource address is that of a device + * @res_addr: resource address struct + * + * Return value: + * 1 if AF / 0 if not AF + **/ +static inline int ipr_is_device(struct ipr_res_addr *res_addr) +{ + if ((res_addr->bus < IPR_MAX_NUM_BUSES) && + (res_addr->target < IPR_MAX_NUM_TARGETS_PER_BUS)) + return 1; + + return 0; +} + +/** + * ipr_sdt_is_fmt2 - Determine if a SDT address is in format 2 + * @sdt_word: SDT address + * + * Return value: + * 1 if format 2 / 0 if not + **/ +static inline int ipr_sdt_is_fmt2(u32 sdt_word) +{ + u32 bar_sel = IPR_GET_FMT2_BAR_SEL(sdt_word); + + switch (bar_sel) { + case IPR_SDT_FMT2_BAR0_SEL: + case IPR_SDT_FMT2_BAR1_SEL: + case IPR_SDT_FMT2_BAR2_SEL: + case IPR_SDT_FMT2_BAR3_SEL: + case IPR_SDT_FMT2_BAR4_SEL: + case IPR_SDT_FMT2_BAR5_SEL: + case IPR_SDT_FMT2_EXP_ROM_SEL: + return 1; + }; + + return 0; +} + +#endif diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c new file mode 100644 index 000000000..4277db3b6 --- /dev/null +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -0,0 +1,1042 @@ +/* +* sym53c500_cs.c Bob Tracy (rct@frus.com) +* +* A rewrite of the pcmcia-cs add-on driver for newer (circa 1997) +* New Media Bus Toaster PCMCIA SCSI cards using the Symbios Logic +* 53c500 controller: intended for use with 2.6 and later kernels. +* The pcmcia-cs add-on version of this driver is not supported +* beyond 2.4. It consisted of three files with history/copyright +* information as follows: +* +* SYM53C500.h +* Bob Tracy (rct@frus.com) +* Original by Tom Corner (tcorner@via.at). +* Adapted from NCR53c406a.h which is Copyrighted (C) 1994 +* Normunds Saumanis (normunds@rx.tech.swh.lv) +* +* SYM53C500.c +* Bob Tracy (rct@frus.com) +* Original driver by Tom Corner (tcorner@via.at) was adapted +* from NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996 +* Normunds Saumanis (normunds@fi.ibm.com) +* +* sym53c500.c +* Bob Tracy (rct@frus.com) +* Original by Tom Corner (tcorner@via.at) was adapted from a +* driver for the Qlogic SCSI card written by +* David Hinds (dhinds@allegro.stanford.edu). +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* 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. +*/ + +#define SYM53C500_DEBUG 0 +#define VERBOSE_SYM53C500_DEBUG 0 + +/* +* Set this to 0 if you encounter kernel lockups while transferring +* data in PIO mode. Note this can be changed via "sysfs". +*/ +#define USE_FAST_PIO 1 + +/* =============== End of user configurable parameters ============== */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* ================================================================== */ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"sym53c500_cs.c 0.9b 2004/05/10 (Bob Tracy)"; +#else +#define DEBUG(n, args...) +#endif + +/* ================================================================== */ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static unsigned int irq_mask = 0xdeb8; /* 3, 6, 7, 9-12, 14, 15 */ +static int irq_list[4] = { -1 }; +static int num_irqs = 1; + +module_param(irq_mask, int, 0); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xdeb8)"); +module_param_array(irq_list, int, num_irqs, 0); +MODULE_PARM_DESC(irq_list, "Comma-separated list of up to 4 IRQs to try (default: auto select)."); + +/* ================================================================== */ + +#define SYNC_MODE 0 /* Synchronous transfer mode */ + +/* Default configuration */ +#define C1_IMG 0x07 /* ID=7 */ +#define C2_IMG 0x48 /* FE SCSI2 */ +#define C3_IMG 0x20 /* CDB */ +#define C4_IMG 0x04 /* ANE */ +#define C5_IMG 0xa4 /* ? changed from b6= AA PI SIE POL */ +#define C7_IMG 0x80 /* added for SYM53C500 t. corner */ + +/* Hardware Registers: offsets from io_port (base) */ + +/* Control Register Set 0 */ +#define TC_LSB 0x00 /* transfer counter lsb */ +#define TC_MSB 0x01 /* transfer counter msb */ +#define SCSI_FIFO 0x02 /* scsi fifo register */ +#define CMD_REG 0x03 /* command register */ +#define STAT_REG 0x04 /* status register */ +#define DEST_ID 0x04 /* selection/reselection bus id */ +#define INT_REG 0x05 /* interrupt status register */ +#define SRTIMOUT 0x05 /* select/reselect timeout reg */ +#define SEQ_REG 0x06 /* sequence step register */ +#define SYNCPRD 0x06 /* synchronous transfer period */ +#define FIFO_FLAGS 0x07 /* indicates # of bytes in fifo */ +#define SYNCOFF 0x07 /* synchronous offset register */ +#define CONFIG1 0x08 /* configuration register */ +#define CLKCONV 0x09 /* clock conversion register */ +/* #define TESTREG 0x0A */ /* test mode register */ +#define CONFIG2 0x0B /* configuration 2 register */ +#define CONFIG3 0x0C /* configuration 3 register */ +#define CONFIG4 0x0D /* configuration 4 register */ +#define TC_HIGH 0x0E /* transfer counter high */ +/* #define FIFO_BOTTOM 0x0F */ /* reserve FIFO byte register */ + +/* Control Register Set 1 */ +/* #define JUMPER_SENSE 0x00 */ /* jumper sense port reg (r/w) */ +/* #define SRAM_PTR 0x01 */ /* SRAM address pointer reg (r/w) */ +/* #define SRAM_DATA 0x02 */ /* SRAM data register (r/w) */ +#define PIO_FIFO 0x04 /* PIO FIFO registers (r/w) */ +/* #define PIO_FIFO1 0x05 */ /* */ +/* #define PIO_FIFO2 0x06 */ /* */ +/* #define PIO_FIFO3 0x07 */ /* */ +#define PIO_STATUS 0x08 /* PIO status (r/w) */ +/* #define ATA_CMD 0x09 */ /* ATA command/status reg (r/w) */ +/* #define ATA_ERR 0x0A */ /* ATA features/error reg (r/w) */ +#define PIO_FLAG 0x0B /* PIO flag interrupt enable (r/w) */ +#define CONFIG5 0x09 /* configuration 5 register */ +/* #define SIGNATURE 0x0E */ /* signature register (r) */ +/* #define CONFIG6 0x0F */ /* configuration 6 register (r) */ +#define CONFIG7 0x0d + +/* select register set 0 */ +#define REG0(x) (outb(C4_IMG, (x) + CONFIG4)) +/* select register set 1 */ +#define REG1(x) outb(C7_IMG, (x) + CONFIG7); outb(C5_IMG, (x) + CONFIG5) + +#if SYM53C500_DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#if VERBOSE_SYM53C500_DEBUG +#define VDEB(x) x +#else +#define VDEB(x) +#endif + +#define LOAD_DMA_COUNT(x, count) \ + outb(count & 0xff, (x) + TC_LSB); \ + outb((count >> 8) & 0xff, (x) + TC_MSB); \ + outb((count >> 16) & 0xff, (x) + TC_HIGH); + +/* Chip commands */ +#define DMA_OP 0x80 + +#define SCSI_NOP 0x00 +#define FLUSH_FIFO 0x01 +#define CHIP_RESET 0x02 +#define SCSI_RESET 0x03 +#define RESELECT 0x40 +#define SELECT_NO_ATN 0x41 +#define SELECT_ATN 0x42 +#define SELECT_ATN_STOP 0x43 +#define ENABLE_SEL 0x44 +#define DISABLE_SEL 0x45 +#define SELECT_ATN3 0x46 +#define RESELECT3 0x47 +#define TRANSFER_INFO 0x10 +#define INIT_CMD_COMPLETE 0x11 +#define MSG_ACCEPT 0x12 +#define TRANSFER_PAD 0x18 +#define SET_ATN 0x1a +#define RESET_ATN 0x1b +#define SEND_MSG 0x20 +#define SEND_STATUS 0x21 +#define SEND_DATA 0x22 +#define DISCONN_SEQ 0x23 +#define TERMINATE_SEQ 0x24 +#define TARG_CMD_COMPLETE 0x25 +#define DISCONN 0x27 +#define RECV_MSG 0x28 +#define RECV_CMD 0x29 +#define RECV_DATA 0x2a +#define RECV_CMD_SEQ 0x2b +#define TARGET_ABORT_DMA 0x04 + +/* ================================================================== */ + +struct scsi_info_t { + dev_link_t link; + dev_node_t node; + struct Scsi_Host *host; + unsigned short manf_id; +}; + +/* +* Repository for per-instance host data. +*/ +struct sym53c500_data { + struct scsi_cmnd *current_SC; + int fast_pio; +}; + +enum Phase { + idle, + data_out, + data_in, + command_ph, + status_ph, + message_out, + message_in +}; + +/* ================================================================== */ + +/* +* Global (within this module) variables other than +* sym53c500_driver_template (the scsi_host_template). +*/ +static dev_link_t *dev_list; +static dev_info_t dev_info = "sym53c500_cs"; + +/* ================================================================== */ + +static void +chip_init(int io_port) +{ + REG1(io_port); + outb(0x01, io_port + PIO_STATUS); + outb(0x00, io_port + PIO_FLAG); + + outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ + outb(C3_IMG, io_port + CONFIG3); + outb(C2_IMG, io_port + CONFIG2); + outb(C1_IMG, io_port + CONFIG1); + + outb(0x05, io_port + CLKCONV); /* clock conversion factor */ + outb(0x9C, io_port + SRTIMOUT); /* Selection timeout */ + outb(0x05, io_port + SYNCPRD); /* Synchronous transfer period */ + outb(SYNC_MODE, io_port + SYNCOFF); /* synchronous mode */ +} + +static void +SYM53C500_int_host_reset(int io_port) +{ + outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ + outb(CHIP_RESET, io_port + CMD_REG); + outb(SCSI_NOP, io_port + CMD_REG); /* required after reset */ + outb(SCSI_RESET, io_port + CMD_REG); + chip_init(io_port); +} + +static __inline__ int +SYM53C500_pio_read(int fast_pio, int base, unsigned char *request, unsigned int reqlen) +{ + int i; + int len; /* current scsi fifo size */ + + REG1(base); + while (reqlen) { + i = inb(base + PIO_STATUS); + /* VDEB(printk("pio_status=%x\n", i)); */ + if (i & 0x80) + return 0; + + switch (i & 0x1e) { + default: + case 0x10: /* fifo empty */ + len = 0; + break; + case 0x0: + len = 1; + break; + case 0x8: /* fifo 1/3 full */ + len = 42; + break; + case 0xc: /* fifo 2/3 full */ + len = 84; + break; + case 0xe: /* fifo full */ + len = 128; + break; + } + + if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ + return 0; + } + + if (len) { + if (len > reqlen) + len = reqlen; + + if (fast_pio && len > 3) { + insl(base + PIO_FIFO, request, len >> 2); + request += len & 0xfc; + reqlen -= len & 0xfc; + } else { + while (len--) { + *request++ = inb(base + PIO_FIFO); + reqlen--; + } + } + } + } + return 0; +} + +static __inline__ int +SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int reqlen) +{ + int i = 0; + int len; /* current scsi fifo size */ + + REG1(base); + while (reqlen && !(i & 0x40)) { + i = inb(base + PIO_STATUS); + /* VDEB(printk("pio_status=%x\n", i)); */ + if (i & 0x80) /* error */ + return 0; + + switch (i & 0x1e) { + case 0x10: + len = 128; + break; + case 0x0: + len = 84; + break; + case 0x8: + len = 42; + break; + case 0xc: + len = 1; + break; + default: + case 0xe: + len = 0; + break; + } + + if (len) { + if (len > reqlen) + len = reqlen; + + if (fast_pio && len > 3) { + outsl(base + PIO_FIFO, request, len >> 2); + request += len & 0xfc; + reqlen -= len & 0xfc; + } else { + while (len--) { + outb(*request++, base + PIO_FIFO); + reqlen--; + } + } + } + } + return 0; +} + +static irqreturn_t +SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + struct Scsi_Host *dev = dev_id; + DEB(unsigned char fifo_size;) + DEB(unsigned char seq_reg;) + unsigned char status, int_reg; + unsigned char pio_status; + struct scatterlist *sglist; + unsigned int sgcount; + int port_base = dev->io_port; + struct sym53c500_data *data = + (struct sym53c500_data *)dev->hostdata; + struct scsi_cmnd *curSC = data->current_SC; + int fast_pio = data->fast_pio; + + spin_lock_irqsave(dev->host_lock, flags); + + VDEB(printk("SYM53C500_intr called\n")); + + REG1(port_base); + pio_status = inb(port_base + PIO_STATUS); + REG0(port_base); + status = inb(port_base + STAT_REG); + DEB(seq_reg = inb(port_base + SEQ_REG)); + int_reg = inb(port_base + INT_REG); + DEB(fifo_size = inb(port_base + FIFO_FLAGS) & 0x1f); + +#if SYM53C500_DEBUG + printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", + status, seq_reg, int_reg, fifo_size); + printk(", pio=%02x\n", pio_status); +#endif /* SYM53C500_DEBUG */ + + if (int_reg & 0x80) { /* SCSI reset intr */ + DEB(printk("SYM53C500: reset intr received\n")); + curSC->result = DID_RESET << 16; + goto idle_out; + } + + if (pio_status & 0x80) { + printk("SYM53C500: Warning: PIO error!\n"); + curSC->result = DID_ERROR << 16; + goto idle_out; + } + + if (status & 0x20) { /* Parity error */ + printk("SYM53C500: Warning: parity error!\n"); + curSC->result = DID_PARITY << 16; + goto idle_out; + } + + if (status & 0x40) { /* Gross error */ + printk("SYM53C500: Warning: gross error!\n"); + curSC->result = DID_ERROR << 16; + goto idle_out; + } + + if (int_reg & 0x20) { /* Disconnect */ + DEB(printk("SYM53C500: disconnect intr received\n")); + if (curSC->SCp.phase != message_in) { /* Unexpected disconnect */ + curSC->result = DID_NO_CONNECT << 16; + } else { /* Command complete, return status and message */ + curSC->result = (curSC->SCp.Status & 0xff) + | ((curSC->SCp.Message & 0xff) << 8) | (DID_OK << 16); + } + goto idle_out; + } + + switch (status & 0x07) { /* scsi phase */ + case 0x00: /* DATA-OUT */ + if (int_reg & 0x10) { /* Target requesting info transfer */ + curSC->SCp.phase = data_out; + VDEB(printk("SYM53C500: Data-Out phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */ + outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); + if (!curSC->use_sg) /* Don't use scatter-gather */ + SYM53C500_pio_write(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen); + else { /* use scatter-gather */ + sgcount = curSC->use_sg; + sglist = curSC->request_buffer; + while (sgcount--) { + SYM53C500_pio_write(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length); + sglist++; + } + } + REG0(port_base); + } + break; + + case 0x01: /* DATA-IN */ + if (int_reg & 0x10) { /* Target requesting info transfer */ + curSC->SCp.phase = data_in; + VDEB(printk("SYM53C500: Data-In phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */ + outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); + if (!curSC->use_sg) /* Don't use scatter-gather */ + SYM53C500_pio_read(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen); + else { /* Use scatter-gather */ + sgcount = curSC->use_sg; + sglist = curSC->request_buffer; + while (sgcount--) { + SYM53C500_pio_read(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length); + sglist++; + } + } + REG0(port_base); + } + break; + + case 0x02: /* COMMAND */ + curSC->SCp.phase = command_ph; + printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n"); + break; + + case 0x03: /* STATUS */ + curSC->SCp.phase = status_ph; + VDEB(printk("SYM53C500: Status phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + outb(INIT_CMD_COMPLETE, port_base + CMD_REG); + break; + + case 0x04: /* Reserved */ + case 0x05: /* Reserved */ + printk("SYM53C500: WARNING: Reserved phase!!!\n"); + break; + + case 0x06: /* MESSAGE-OUT */ + DEB(printk("SYM53C500: Message-Out phase\n")); + curSC->SCp.phase = message_out; + outb(SET_ATN, port_base + CMD_REG); /* Reject the message */ + outb(MSG_ACCEPT, port_base + CMD_REG); + break; + + case 0x07: /* MESSAGE-IN */ + VDEB(printk("SYM53C500: Message-In phase\n")); + curSC->SCp.phase = message_in; + + curSC->SCp.Status = inb(port_base + SCSI_FIFO); + curSC->SCp.Message = inb(port_base + SCSI_FIFO); + + VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); + DEB(printk("Status = %02x Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message)); + + if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) { + outb(SET_ATN, port_base + CMD_REG); /* Reject message */ + DEB(printk("Discarding SAVE_POINTERS message\n")); + } + outb(MSG_ACCEPT, port_base + CMD_REG); + break; + } +out: + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; + +idle_out: + curSC->SCp.phase = idle; + curSC->scsi_done(curSC); + goto out; +} + +static void +SYM53C500_release(dev_link_t *link) +{ + struct scsi_info_t *info = link->priv; + struct Scsi_Host *shost = info->host; + + DEBUG(0, "SYM53C500_release(0x%p)\n", link); + + /* + * Do this before releasing/freeing resources. + */ + scsi_remove_host(shost); + + /* + * Interrupts getting hosed on card removal. Try + * the following code, mostly from qlogicfas.c. + */ + if (shost->irq) + free_irq(shost->irq, shost); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + + link->dev = NULL; + + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + + scsi_host_put(shost); +} /* SYM53C500_release */ + +static const char* +SYM53C500_info(struct Scsi_Host *SChost) +{ + static char info_msg[256]; + struct sym53c500_data *data = + (struct sym53c500_data *)SChost->hostdata; + + DEB(printk("SYM53C500_info called\n")); + (void)snprintf(info_msg, sizeof(info_msg), + "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", + SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow"); + return (info_msg); +} + +static int +SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +{ + int i; + int port_base = SCpnt->device->host->io_port; + struct sym53c500_data *data = + (struct sym53c500_data *)SCpnt->device->host->hostdata; + + VDEB(printk("SYM53C500_queue called\n")); + + DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", + SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, + SCpnt->device->lun, SCpnt->request_bufflen)); + + VDEB(for (i = 0; i < SCpnt->cmd_len; i++) + printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); + VDEB(printk("\n")); + + data->current_SC = SCpnt; + data->current_SC->scsi_done = done; + data->current_SC->SCp.phase = command_ph; + data->current_SC->SCp.Status = 0; + data->current_SC->SCp.Message = 0; + + /* We are locked here already by the mid layer */ + REG0(port_base); + outb(SCpnt->device->id, port_base + DEST_ID); /* set destination */ + outb(FLUSH_FIFO, port_base + CMD_REG); /* reset the fifos */ + + for (i = 0; i < SCpnt->cmd_len; i++) { + outb(SCpnt->cmnd[i], port_base + SCSI_FIFO); + } + outb(SELECT_NO_ATN, port_base + CMD_REG); + + return 0; +} + +static int +SYM53C500_host_reset(struct scsi_cmnd *SCpnt) +{ + int port_base = SCpnt->device->host->io_port; + + DEB(printk("SYM53C500_host_reset called\n")); + SYM53C500_int_host_reset(port_base); + + return SUCCESS; +} + +static int +SYM53C500_biosparm(struct scsi_device *disk, + struct block_device *dev, + sector_t capacity, int *info_array) +{ + int size; + + DEB(printk("SYM53C500_biosparm called\n")); + + size = capacity; + info_array[0] = 64; /* heads */ + info_array[1] = 32; /* sectors */ + info_array[2] = size >> 11; /* cylinders */ + if (info_array[2] > 1024) { /* big disk */ + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = size / (255 * 63); + } + return 0; +} + +static ssize_t +SYM53C500_show_pio(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *SHp = class_to_shost(cdev); + struct sym53c500_data *data = + (struct sym53c500_data *)SHp->hostdata; + + return snprintf(buf, 4, "%d\n", data->fast_pio); +} + +static ssize_t +SYM53C500_store_pio(struct class_device *cdev, const char *buf, size_t count) +{ + int pio; + struct Scsi_Host *SHp = class_to_shost(cdev); + struct sym53c500_data *data = + (struct sym53c500_data *)SHp->hostdata; + + pio = simple_strtoul(buf, NULL, 0); + if (pio == 0 || pio == 1) { + data->fast_pio = pio; + return count; + } + else + return -EINVAL; +} + +/* +* SCSI HBA device attributes we want to +* make available via sysfs. +*/ +static struct class_device_attribute SYM53C500_pio_attr = { + .attr = { + .name = "fast_pio", + .mode = (S_IRUGO | S_IWUSR), + }, + .show = SYM53C500_show_pio, + .store = SYM53C500_store_pio, +}; + +static struct class_device_attribute *SYM53C500_shost_attrs[] = { + &SYM53C500_pio_attr, + NULL, +}; + +/* +* scsi_host_template initializer +*/ +static struct scsi_host_template sym53c500_driver_template = { + .module = THIS_MODULE, + .name = "SYM53C500", + .info = SYM53C500_info, + .queuecommand = SYM53C500_queue, + .eh_host_reset_handler = SYM53C500_host_reset, + .bios_param = SYM53C500_biosparm, + .proc_name = "SYM53C500", + .can_queue = 1, + .this_id = 7, + .sg_tablesize = 32, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = SYM53C500_shost_attrs +}; + +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static void +SYM53C500_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + int irq_level, port_base; + unsigned short tuple_data[32]; + struct Scsi_Host *host; + struct scsi_host_template *tpnt = &sym53c500_driver_template; + struct sym53c500_data *data; + + DEBUG(0, "SYM53C500_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *)tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + link->conf.ConfigBase = parse.config.base; + + tuple.DesiredTuple = CISTPL_MANFID; + if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) + info->manf_id = le16_to_cpu(tuple.TupleData[0]); + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + while (1) { + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; + + if (link->io.BasePort1 != 0) { + i = pcmcia_request_io(handle, &link->io); + if (i == CS_SUCCESS) + break; + } +next_entry: + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + } + + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + + /* + * That's the trouble with copying liberally from another driver. + * Some things probably aren't relevant, and I suspect this entire + * section dealing with manufacturer IDs can be scrapped. --rct + */ + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + /* set ATAcmd */ + outb(0xb4, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); + } + + /* + * irq_level == 0 implies tpnt->can_queue == 0, which + * is not supported in 2.6. Thus, only irq_level > 0 + * will be allowed. + * + * Possible port_base values are as follows: + * + * 0x130, 0x230, 0x280, 0x290, + * 0x320, 0x330, 0x340, 0x350 + */ + port_base = link->io.BasePort1; + irq_level = link->irq.AssignedIRQ; + + DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n", + port_base, irq_level, USE_FAST_PIO);) + + chip_init(port_base); + + host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data)); + if (!host) { + printk("SYM53C500: Unable to register host, giving up.\n"); + goto err_release; + } + + data = (struct sym53c500_data *)host->hostdata; + + if (irq_level > 0) { + if (request_irq(irq_level, SYM53C500_intr, 0, "SYM53C500", host)) { + printk("SYM53C500: unable to allocate IRQ %d\n", irq_level); + goto err_free_scsi; + } + DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level)); + } else if (irq_level == 0) { + DEB(printk("SYM53C500: No interrupts detected\n")); + goto err_free_scsi; + } else { + DEB(printk("SYM53C500: Shouldn't get here!\n")); + goto err_free_scsi; + } + + host->unique_id = port_base; + host->irq = irq_level; + host->io_port = port_base; + host->n_io_port = 0x10; + host->dma_channel = -1; + + /* + * Note fast_pio is set to USE_FAST_PIO by + * default, but can be changed via "sysfs". + */ + data->fast_pio = USE_FAST_PIO; + + sprintf(info->node.dev_name, "scsi%d", host->host_no); + link->dev = &info->node; + info->host = host; + + if (scsi_add_host(host, NULL)) + goto err_free_irq; + + scsi_scan_host(host); + + goto out; /* SUCCESS */ + +err_free_irq: + free_irq(irq_level, host); +err_free_scsi: + scsi_host_put(host); +err_release: + release_region(port_base, 0x10); + printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); + +out: + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + SYM53C500_release(link); + return; +} /* SYM53C500_config */ + +static int +SYM53C500_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct scsi_info_t *info = link->priv; + + DEBUG(1, "SYM53C500_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + SYM53C500_release(link); + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + SYM53C500_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + pcmcia_request_configuration(link->handle, &link->conf); + /* See earlier comment about manufacturer IDs. */ + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + outb(0x80, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); + } + /* + * If things don't work after a "resume", + * this is a good place to start looking. + */ + SYM53C500_int_host_reset(link->io.BasePort1); + } + break; + } + return 0; +} /* SYM53C500_event */ + +static void +SYM53C500_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "SYM53C500_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) + SYM53C500_release(link); + + if (link->handle) + pcmcia_deregister_client(link->handle); + + /* Unlink device structure, free bits. */ + *linkp = link->next; + kfree(link->priv); + link->priv = NULL; +} /* SYM53C500_detach */ + +static dev_link_t * +SYM53C500_attach(void) +{ + struct scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "SYM53C500_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &SYM53C500_event; + client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = pcmcia_register_client(&link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + SYM53C500_detach(link); + return NULL; + } + + return link; +} /* SYM53C500_attach */ + +MODULE_AUTHOR("Bob Tracy "); +MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver"); +MODULE_LICENSE("GPL"); + +static struct pcmcia_driver sym53c500_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "sym53c500_cs", + }, + .attach = SYM53C500_attach, + .detach = SYM53C500_detach, +}; + +static int __init +init_sym53c500_cs(void) +{ + return pcmcia_register_driver(&sym53c500_cs_driver); +} + +static void __exit +exit_sym53c500_cs(void) +{ + pcmcia_unregister_driver(&sym53c500_cs_driver); +} + +module_init(init_sym53c500_cs); +module_exit(exit_sym53c500_cs); diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 5b6ce0a88..32c9cd413 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -56,7 +56,7 @@ #include #include "scsi.h" -#include +#include "hosts.h" #include "qlogicfas408.h" /*----------------------------------------------------------------*/ diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h new file mode 100644 index 000000000..f01cbd66c --- /dev/null +++ b/drivers/scsi/qlogicfas408.h @@ -0,0 +1,120 @@ +/* to be used by qlogicfas and qlogic_cs */ +#ifndef __QLOGICFAS408_H +#define __QLOGICFAS408_H + +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable. */ + +#define QL_TURBO_PDMA 1 + +/* This should be 1 to enable parity detection */ + +#define QL_ENABLE_PARITY 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back + without requiring a cold boot. It does take some time to recover from a + reset, so it is slower, and I have seen timeouts so that devices weren't + recognized when this was set. */ + +#define QL_RESET_AT_START 0 + +/* crystal frequency in megahertz (for offset 5 and 9) + Please set this for your card. Most Qlogic cards are 40 Mhz. The + Control Concepts ISA (not VLB) is 24 Mhz */ + +#define XTALFREQ 40 + +/**********/ +/* DANGER! modify these at your own risk */ +/* SLOWCABLE can usually be reset to zero if you have a clean setup and + proper termination. The rest are for synchronous transfers and other + advanced features if your device can transfer faster than 5Mb/sec. + If you are really curious, email me for a quick howto until I have + something official */ +/**********/ + +/*****/ +/* config register 1 (offset 8) options */ +/* This needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 1 + +/*****/ +/* offset 0xc */ +/* This will set fast (10Mhz) synchronous timing when set to 1 + For this to have an effect, FASTCLK must also be 1 */ +#define FASTSCSI 0 + +/* This when set to 1 will set a faster sync transfer rate */ +#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ + +/*****/ +/* offset 6 */ +/* This is the sync transfer divisor, XTALFREQ/X will be the maximum + achievable data rate (assuming the rest of the system is capable + and set properly) */ +#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ + +/*****/ +/* offset 7 */ +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ + +struct qlogicfas408_priv { + int qbase; /* Port */ + int qinitid; /* initiator ID */ + int qabort; /* Flag to cause an abort */ + int qlirq; /* IRQ being used */ + int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */ + char qinfo[80]; /* description */ + Scsi_Cmnd *qlcmd; /* current command being processed */ + struct Scsi_Host *shost; /* pointer back to host */ + struct qlogicfas408_priv *next; /* next private struct */ +}; + +/* The qlogic card uses two register maps - These macros select which one */ +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | int_type, qbase + 0xd )) + +/* following is watchdog timeout in microseconds */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#define rtrc(i) {} + +#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0]) +#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) + +irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs); +int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int qlogicfas408_biosparam(struct scsi_device * disk, + struct block_device *dev, + sector_t capacity, int ip[]); +int qlogicfas408_abort(Scsi_Cmnd * cmd); +int qlogicfas408_bus_reset(Scsi_Cmnd * cmd); +int qlogicfas408_host_reset(Scsi_Cmnd * cmd); +int qlogicfas408_device_reset(Scsi_Cmnd * cmd); +const char *qlogicfas408_info(struct Scsi_Host *host); +int qlogicfas408_get_chip_type(int qbase, int int_type); +void qlogicfas408_setup(int qbase, int id, int int_type); +int qlogicfas408_detect(int qbase, int int_type); +void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv); +#endif /* __QLOGICFAS408_H */ + diff --git a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h new file mode 100644 index 000000000..6e7e96b9e --- /dev/null +++ b/drivers/scsi/sata_promise.h @@ -0,0 +1,154 @@ +/* + * sata_promise.h - Promise SATA common definitions and inline funcs + * + * Copyright 2003-2004 Red Hat, Inc. + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + */ + +#ifndef __SATA_PROMISE_H__ +#define __SATA_PROMISE_H__ + +#include + +enum pdc_packet_bits { + PDC_PKT_READ = (1 << 2), + PDC_PKT_NODATA = (1 << 3), + + PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5), + PDC_PKT_CLEAR_BSY = (1 << 4), + PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4), + PDC_LAST_REG = (1 << 3), + + PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1), +}; + +static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf, + dma_addr_t sg_table, + unsigned int devno, u8 *buf) +{ + u8 dev_reg; + u32 *buf32 = (u32 *) buf; + + /* set control bits (byte 0), zero delay seq id (byte 3), + * and seq id (byte 2) + */ + switch (tf->protocol) { + case ATA_PROT_DMA: + if (!(tf->flags & ATA_TFLAG_WRITE)) + buf32[0] = cpu_to_le32(PDC_PKT_READ); + else + buf32[0] = 0; + break; + + case ATA_PROT_NODATA: + buf32[0] = cpu_to_le32(PDC_PKT_NODATA); + break; + + default: + BUG(); + break; + } + + buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */ + buf32[2] = 0; /* no next-packet */ + + if (devno == 0) + dev_reg = ATA_DEVICE_OBS; + else + dev_reg = ATA_DEVICE_OBS | ATA_DEV1; + + /* select device */ + buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE; + buf[13] = dev_reg; + + /* device control register */ + buf[14] = (1 << 5) | PDC_REG_DEVCTL; + buf[15] = tf->ctl; + + return 16; /* offset of next byte */ +} + +static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf, + unsigned int i) +{ + if (tf->flags & ATA_TFLAG_DEVICE) { + buf[i++] = (1 << 5) | ATA_REG_DEVICE; + buf[i++] = tf->device; + } + + /* and finally the command itself; also includes end-of-pkt marker */ + buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD; + buf[i++] = tf->command; + + return i; +} + +static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i) +{ + /* the "(1 << 5)" should be read "(count << 5)" */ + + /* ATA command block registers */ + buf[i++] = (1 << 5) | ATA_REG_FEATURE; + buf[i++] = tf->feature; + + buf[i++] = (1 << 5) | ATA_REG_NSECT; + buf[i++] = tf->nsect; + + buf[i++] = (1 << 5) | ATA_REG_LBAL; + buf[i++] = tf->lbal; + + buf[i++] = (1 << 5) | ATA_REG_LBAM; + buf[i++] = tf->lbam; + + buf[i++] = (1 << 5) | ATA_REG_LBAH; + buf[i++] = tf->lbah; + + return i; +} + +static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i) +{ + /* the "(2 << 5)" should be read "(count << 5)" */ + + /* ATA command block registers */ + buf[i++] = (2 << 5) | ATA_REG_FEATURE; + buf[i++] = tf->hob_feature; + buf[i++] = tf->feature; + + buf[i++] = (2 << 5) | ATA_REG_NSECT; + buf[i++] = tf->hob_nsect; + buf[i++] = tf->nsect; + + buf[i++] = (2 << 5) | ATA_REG_LBAL; + buf[i++] = tf->hob_lbal; + buf[i++] = tf->lbal; + + buf[i++] = (2 << 5) | ATA_REG_LBAM; + buf[i++] = tf->hob_lbam; + buf[i++] = tf->lbam; + + buf[i++] = (2 << 5) | ATA_REG_LBAH; + buf[i++] = tf->hob_lbah; + buf[i++] = tf->lbah; + + return i; +} + + +#endif /* __SATA_PROMISE_H__ */ diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 75013729e..3268fdf7e 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -826,14 +826,14 @@ out: static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol == ATA_PROT_PIO) + if (tf->protocol != ATA_PROT_DMA) ata_tf_load_mmio(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol == ATA_PROT_PIO) + if (tf->protocol != ATA_PROT_DMA) ata_exec_command_mmio(ap, tf); } diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index a0d988dc9..abbbe3fc3 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -437,7 +437,7 @@ static struct pnp_driver serial_pnp_driver = { .name = "serial", .id_table = pnp_dev_table, .probe = serial_pnp_probe, - .remove = serial_pnp_remove, + .remove = __devexit_p(serial_pnp_remove), }; static int __init serial8250_pnp_init(void) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 23f452ad3..8e6060f42 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -259,6 +259,7 @@ config SERIAL_S3C2410 config SERIAL_S3C2410_CONSOLE bool "Support for console on S3C2410 serial port" depends on SERIAL_S3C2410=y + select SERIAL_CORE_CONSOLE help Allow selection of the S3C2410 on-board serial ports for use as an virtual console. diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 84b4a8e0a..22a02bd69 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -37,7 +37,7 @@ #define SERIAL_S3C2410_NAME "ttySAC" #define SERIAL_S3C2410_MAJOR 204 -#define SERIAL_S3C2410_MINOR 4 +#define SERIAL_S3C2410_MINOR 64 /* we can support 3 uarts, but not always use them */ diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c new file mode 100644 index 000000000..38c64f656 --- /dev/null +++ b/drivers/usb/core/sysfs.c @@ -0,0 +1,229 @@ +/* + * drivers/usb/core/sysfs.c + * + * (C) Copyright 2002 David Brownell + * (C) Copyright 2002 Greg Kroah-Hartman + * (C) Copyright 2002 IBM Corp. + * + * All of the sysfs file attributes for usb devices and interfaces. + * + */ + + +#include +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include + +#include "usb.h" + +/* Active configuration fields */ +#define usb_actconfig_show(field, multiplier, format_string) \ +static ssize_t show_##field (struct device *dev, char *buf) \ +{ \ + struct usb_device *udev; \ + \ + udev = to_usb_device (dev); \ + if (udev->actconfig) \ + return sprintf (buf, format_string, \ + udev->actconfig->desc.field * multiplier); \ + else \ + return 0; \ +} \ + +#define usb_actconfig_attr(field, multiplier, format_string) \ +usb_actconfig_show(field, multiplier, format_string) \ +static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") +usb_actconfig_attr (bmAttributes, 1, "%2x\n") +usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") + +/* configuration value is always present, and r/w */ +usb_actconfig_show(bConfigurationValue, 1, "%u\n"); + +static ssize_t +set_bConfigurationValue (struct device *dev, const char *buf, size_t count) +{ + struct usb_device *udev = udev = to_usb_device (dev); + int config, value; + + if (sscanf (buf, "%u", &config) != 1 || config > 255) + return -EINVAL; + down(&udev->serialize); + value = usb_set_configuration (udev, config); + up(&udev->serialize); + return (value < 0) ? value : count; +} + +static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, + show_bConfigurationValue, set_bConfigurationValue); + +/* String fields */ +#define usb_string_attr(name, field) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + struct usb_device *udev; \ + int len; \ + \ + udev = to_usb_device (dev); \ + len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE); \ + if (len < 0) \ + return 0; \ + buf[len] = '\n'; \ + buf[len+1] = 0; \ + return len+1; \ +} \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); + +usb_string_attr(product, iProduct); +usb_string_attr(manufacturer, iManufacturer); +usb_string_attr(serial, iSerialNumber); + +static ssize_t +show_speed (struct device *dev, char *buf) +{ + struct usb_device *udev; + char *speed; + + udev = to_usb_device (dev); + + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + return sprintf (buf, "%s\n", speed); +} +static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); + +static ssize_t +show_devnum (struct device *dev, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device (dev); + return sprintf (buf, "%d\n", udev->devnum); +} +static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); + +static ssize_t +show_version (struct device *dev, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device (dev); + return sprintf (buf, "%2x.%02x\n", udev->descriptor.bcdUSB >> 8, + udev->descriptor.bcdUSB & 0xff); +} +static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); + +static ssize_t +show_maxchild (struct device *dev, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device (dev); + return sprintf (buf, "%d\n", udev->maxchild); +} +static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); + +/* Descriptor fields */ +#define usb_descriptor_attr(field, format_string) \ +static ssize_t \ +show_##field (struct device *dev, char *buf) \ +{ \ + struct usb_device *udev; \ + \ + udev = to_usb_device (dev); \ + return sprintf (buf, format_string, udev->descriptor.field); \ +} \ +static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +usb_descriptor_attr (idVendor, "%04x\n") +usb_descriptor_attr (idProduct, "%04x\n") +usb_descriptor_attr (bcdDevice, "%04x\n") +usb_descriptor_attr (bDeviceClass, "%02x\n") +usb_descriptor_attr (bDeviceSubClass, "%02x\n") +usb_descriptor_attr (bDeviceProtocol, "%02x\n") +usb_descriptor_attr (bNumConfigurations, "%d\n") + + +void usb_create_sysfs_dev_files (struct usb_device *udev) +{ + struct device *dev = &udev->dev; + + /* current configuration's attributes */ + device_create_file (dev, &dev_attr_bNumInterfaces); + device_create_file (dev, &dev_attr_bConfigurationValue); + device_create_file (dev, &dev_attr_bmAttributes); + device_create_file (dev, &dev_attr_bMaxPower); + + /* device attributes */ + device_create_file (dev, &dev_attr_idVendor); + device_create_file (dev, &dev_attr_idProduct); + device_create_file (dev, &dev_attr_bcdDevice); + device_create_file (dev, &dev_attr_bDeviceClass); + device_create_file (dev, &dev_attr_bDeviceSubClass); + device_create_file (dev, &dev_attr_bDeviceProtocol); + device_create_file (dev, &dev_attr_bNumConfigurations); + + /* speed varies depending on how you connect the device */ + device_create_file (dev, &dev_attr_speed); + // FIXME iff there are other speed configs, show how many + + if (udev->descriptor.iManufacturer) + device_create_file (dev, &dev_attr_manufacturer); + if (udev->descriptor.iProduct) + device_create_file (dev, &dev_attr_product); + if (udev->descriptor.iSerialNumber) + device_create_file (dev, &dev_attr_serial); + + device_create_file (dev, &dev_attr_devnum); + device_create_file (dev, &dev_attr_version); + device_create_file (dev, &dev_attr_maxchild); +} + +/* Interface fields */ +#define usb_intf_attr(field, format_string) \ +static ssize_t \ +show_##field (struct device *dev, char *buf) \ +{ \ + struct usb_interface *intf = to_usb_interface (dev); \ + \ + return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ +} \ +static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +usb_intf_attr (bInterfaceNumber, "%02x\n") +usb_intf_attr (bAlternateSetting, "%2d\n") +usb_intf_attr (bNumEndpoints, "%02x\n") +usb_intf_attr (bInterfaceClass, "%02x\n") +usb_intf_attr (bInterfaceSubClass, "%02x\n") +usb_intf_attr (bInterfaceProtocol, "%02x\n") +usb_intf_attr (iInterface, "%02x\n") + +void usb_create_sysfs_intf_files (struct usb_interface *intf) +{ + device_create_file (&intf->dev, &dev_attr_bInterfaceNumber); + device_create_file (&intf->dev, &dev_attr_bAlternateSetting); + device_create_file (&intf->dev, &dev_attr_bNumEndpoints); + device_create_file (&intf->dev, &dev_attr_bInterfaceClass); + device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass); + device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol); + device_create_file (&intf->dev, &dev_attr_iInterface); +} diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c new file mode 100644 index 000000000..4917b042e --- /dev/null +++ b/drivers/usb/input/touchkitusb.c @@ -0,0 +1,310 @@ +/****************************************************************************** + * touchkitusb.c -- Driver for eGalax TouchKit USB Touchscreens + * + * Copyright (C) 2004 by Daniel Ritz + * Copyright (C) by Todd E. Johnson (mtouchusb.c) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based upon mtouchusb.c + * + *****************************************************************************/ + +//#define DEBUG + +#include +#include +#include +#include +#include +#include + +#if !defined(DEBUG) && defined(CONFIG_USB_DEBUG) +#define DEBUG +#endif +#include + + +#define TOUCHKIT_MIN_XC 0x0 +#define TOUCHKIT_MAX_XC 0x07ff +#define TOUCHKIT_XC_FUZZ 0x0 +#define TOUCHKIT_XC_FLAT 0x0 +#define TOUCHKIT_MIN_YC 0x0 +#define TOUCHKIT_MAX_YC 0x07ff +#define TOUCHKIT_YC_FUZZ 0x0 +#define TOUCHKIT_YC_FLAT 0x0 +#define TOUCHKIT_REPORT_DATA_SIZE 8 + +#define TOUCHKIT_DOWN 0x01 +#define TOUCHKIT_POINT_TOUCH 0x81 +#define TOUCHKIT_POINT_NOTOUCH 0x80 + +#define TOUCHKIT_GET_TOUCHED(dat) ((((dat)[0]) & TOUCHKIT_DOWN) ? 1 : 0) +#define TOUCHKIT_GET_X(dat) (((dat)[3] << 7) | (dat)[4]) +#define TOUCHKIT_GET_Y(dat) (((dat)[1] << 7) | (dat)[2]) + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Daniel Ritz " +#define DRIVER_DESC "eGalax TouchKit USB HID Touchscreen Driver" + +struct touchkit_usb { + unsigned char *data; + dma_addr_t data_dma; + struct urb *irq; + struct usb_device *udev; + struct input_dev input; + int open; + char name[128]; + char phys[64]; +}; + +static struct usb_device_id touchkit_devices[] = { + {USB_DEVICE(0x3823, 0x0001)}, + {USB_DEVICE(0x0eef, 0x0001)}, + {} +}; + +static void touchkit_irq(struct urb *urb, struct pt_regs *regs) +{ + struct touchkit_usb *touchkit = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_regs(&touchkit->input, regs); + input_report_key(&touchkit->input, BTN_TOUCH, + TOUCHKIT_GET_TOUCHED(touchkit->data)); + input_report_abs(&touchkit->input, ABS_X, + TOUCHKIT_GET_X(touchkit->data)); + input_report_abs(&touchkit->input, ABS_Y, + TOUCHKIT_GET_Y(touchkit->data)); + input_sync(&touchkit->input); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int touchkit_open(struct input_dev *input) +{ + struct touchkit_usb *touchkit = input->private; + + if (touchkit->open++) + return 0; + + touchkit->irq->dev = touchkit->udev; + + if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) { + touchkit->open--; + return -EIO; + } + + return 0; +} + +static void touchkit_close(struct input_dev *input) +{ + struct touchkit_usb *touchkit = input->private; + + if (!--touchkit->open) + usb_unlink_urb(touchkit->irq); +} + +static int touchkit_alloc_buffers(struct usb_device *udev, + struct touchkit_usb *touchkit) +{ + touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE, + SLAB_ATOMIC, &touchkit->data_dma); + + if (!touchkit->data) + return -1; + + return 0; +} + +static void touchkit_free_buffers(struct usb_device *udev, + struct touchkit_usb *touchkit) +{ + if (touchkit->data) + usb_buffer_free(udev, TOUCHKIT_REPORT_DATA_SIZE, + touchkit->data, touchkit->data_dma); +} + +static int touchkit_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct touchkit_usb *touchkit; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + char path[64]; + char *buf; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + touchkit = kmalloc(sizeof(struct touchkit_usb), GFP_KERNEL); + if (!touchkit) + return -ENOMEM; + + memset(touchkit, 0, sizeof(struct touchkit_usb)); + touchkit->udev = udev; + + if (touchkit_alloc_buffers(udev, touchkit)) { + ret = -ENOMEM; + goto out_free; + } + + touchkit->input.private = touchkit; + touchkit->input.open = touchkit_open; + touchkit->input.close = touchkit_close; + + usb_make_path(udev, path, 64); + sprintf(touchkit->phys, "%s/input0", path); + + touchkit->input.name = touchkit->name; + touchkit->input.phys = touchkit->phys; + touchkit->input.id.bustype = BUS_USB; + touchkit->input.id.vendor = udev->descriptor.idVendor; + touchkit->input.id.product = udev->descriptor.idProduct; + touchkit->input.id.version = udev->descriptor.bcdDevice; + touchkit->input.dev = &intf->dev; + + touchkit->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + touchkit->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + touchkit->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + /* Used to Scale Compensated Data */ + touchkit->input.absmin[ABS_X] = TOUCHKIT_MIN_XC; + touchkit->input.absmax[ABS_X] = TOUCHKIT_MAX_XC; + touchkit->input.absfuzz[ABS_X] = TOUCHKIT_XC_FUZZ; + touchkit->input.absflat[ABS_X] = TOUCHKIT_XC_FLAT; + touchkit->input.absmin[ABS_Y] = TOUCHKIT_MIN_YC; + touchkit->input.absmax[ABS_Y] = TOUCHKIT_MAX_YC; + touchkit->input.absfuzz[ABS_Y] = TOUCHKIT_YC_FUZZ; + touchkit->input.absflat[ABS_Y] = TOUCHKIT_YC_FLAT; + + buf = kmalloc(63, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out_free_buffers; + } + + if (udev->descriptor.iManufacturer && + usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(touchkit->name, buf); + if (udev->descriptor.iProduct && + usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0) + sprintf(touchkit->name, "%s %s", touchkit->name, buf); + + if (!strlen(touchkit->name)) + sprintf(touchkit->name, "USB Touchscreen %04x:%04x", + touchkit->input.id.vendor, touchkit->input.id.product); + + kfree(buf); + + touchkit->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!touchkit->irq) { + dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__); + ret = -ENOMEM; + goto out_free_buffers; + } + + usb_fill_int_urb(touchkit->irq, touchkit->udev, + usb_rcvintpipe(touchkit->udev, 0x81), + touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, + touchkit_irq, touchkit, endpoint->bInterval); + + input_register_device(&touchkit->input); + + printk(KERN_INFO "input: %s on %s\n", touchkit->name, path); + usb_set_intfdata(intf, touchkit); + + return 0; + +out_free_buffers: + touchkit_free_buffers(udev, touchkit); +out_free: + kfree(touchkit); + return ret; +} + +static void touchkit_disconnect(struct usb_interface *intf) +{ + struct touchkit_usb *touchkit = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + + if (!touchkit) + return; + + dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__); + usb_set_intfdata(intf, NULL); + input_unregister_device(&touchkit->input); + usb_unlink_urb(touchkit->irq); + usb_free_urb(touchkit->irq); + touchkit_free_buffers(interface_to_usbdev(intf), touchkit); + kfree(touchkit); +} + +MODULE_DEVICE_TABLE(usb, touchkit_devices); + +static struct usb_driver touchkit_driver = { + .owner = THIS_MODULE, + .name = "touchkitusb", + .probe = touchkit_probe, + .disconnect = touchkit_disconnect, + .id_table = touchkit_devices, +}; + +static int __init touchkit_init(void) +{ + return usb_register(&touchkit_driver); +} + +static void __exit touchkit_cleanup(void) +{ + usb_deregister(&touchkit_driver); +} + +module_init(touchkit_init); +module_exit(touchkit_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig index eba7ef348..00bf32230 100644 --- a/drivers/usb/media/Kconfig +++ b/drivers/usb/media/Kconfig @@ -108,7 +108,7 @@ config USB_OV511 config USB_PWC tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV && BROKEN + depends on USB && VIDEO_DEV ---help--- Say Y or M here if you want to use one of these Philips & OEM webcams: diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c new file mode 100644 index 000000000..9018774ae --- /dev/null +++ b/drivers/usb/misc/phidgetservo.c @@ -0,0 +1,327 @@ +/* + * USB PhidgetServo driver 1.0 + * + * Copyright (C) 2004 Sean Young + * + * 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 is a driver for the USB PhidgetServo version 2.0 and 3.0 servo + * controllers available at: http://www.phidgets.com/ + * + * Note that the driver takes input as: degrees.minutes + * -23 < degrees < 203 + * 0 < minutes < 59 + * + * CAUTION: Generally you should use 0 < degrees < 180 as anything else + * is probably beyond the range of your servo and may damage it. + */ + +#include +#ifdef CONFIG_USB_DEBUG +#define DEBUG 1 +#endif +#include +#include +#include +#include +#include +#include + +#define DRIVER_AUTHOR "Sean Young " +#define DRIVER_DESC "USB PhidgetServo Driver" + +#define VENDOR_ID_GLAB 0x06c2 +#define DEVICE_ID_4MOTOR_SERVO_30 0x0038 +#define DEVICE_ID_1MOTOR_SERVO_30 0x0039 + +#define VENDOR_ID_WISEGROUP 0x0925 +#define DEVICE_ID_1MOTOR_SERVO_20 0x8101 +#define DEVICE_ID_4MOTOR_SERVO_20 0x8104 + +static struct usb_device_id id_table[] = { + {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_4MOTOR_SERVO_30)}, + {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_1MOTOR_SERVO_30)}, + {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_4MOTOR_SERVO_20)}, + {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_1MOTOR_SERVO_20)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +struct phidget_servo { + struct usb_device *udev; + int version; + int quad_servo; + int pulse[4]; + int degrees[4]; + int minutes[4]; +}; + +static void +change_position_v30(struct phidget_servo *servo, int servo_no, int degrees, + int minutes) +{ + int retval; + unsigned char *buffer; + + buffer = kmalloc(6, GFP_KERNEL); + if (!buffer) { + dev_err(&servo->udev->dev, "%s - out of memory\n", + __FUNCTION__); + return; + } + + /* + * pulse = 0 - 4095 + * angle = 0 - 180 degrees + * + * pulse = angle * 10.6 + 243.8 + */ + servo->pulse[servo_no] = ((degrees*60 + minutes)*106 + 2438*60)/600; + servo->degrees[servo_no]= degrees; + servo->minutes[servo_no]= minutes; + + /* + * The PhidgetServo v3.0 is controlled by sending 6 bytes, + * 4 * 12 bits for each servo. + * + * low = lower 8 bits pulse + * high = higher 4 bits pulse + * + * offset bits + * +---+-----------------+ + * | 0 | low 0 | + * +---+--------+--------+ + * | 1 | high 1 | high 0 | + * +---+--------+--------+ + * | 2 | low 1 | + * +---+-----------------+ + * | 3 | low 2 | + * +---+--------+--------+ + * | 4 | high 3 | high 2 | + * +---+--------+--------+ + * | 5 | low 3 | + * +---+-----------------+ + */ + + buffer[0] = servo->pulse[0] & 0xff; + buffer[1] = (servo->pulse[0] >> 8 & 0x0f) + | (servo->pulse[1] >> 4 & 0xf0); + buffer[2] = servo->pulse[1] & 0xff; + buffer[3] = servo->pulse[2] & 0xff; + buffer[4] = (servo->pulse[2] >> 8 & 0x0f) + | (servo->pulse[3] >> 4 & 0xf0); + buffer[5] = servo->pulse[3] & 0xff; + + dev_dbg(&servo->udev->dev, + "data: %02x %02x %02x %02x %02x %02x\n", + buffer[0], buffer[1], buffer[2], + buffer[3], buffer[4], buffer[5]); + + retval = usb_control_msg(servo->udev, + usb_sndctrlpipe(servo->udev, 0), + 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2 * HZ); + if (retval != 6) + dev_err(&servo->udev->dev, "retval = %d\n", retval); + kfree(buffer); +} + +static void +change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, + int minutes) +{ + int retval; + unsigned char *buffer; + + buffer = kmalloc(2, GFP_KERNEL); + if (!buffer) { + dev_err(&servo->udev->dev, "%s - out of memory\n", + __FUNCTION__); + return; + } + + /* + * angle = 0 - 180 degrees + * pulse = angle + 23 + */ + servo->pulse[servo_no]= degrees + 23; + servo->degrees[servo_no]= degrees; + servo->minutes[servo_no]= 0; + + /* + * The PhidgetServo v2.0 is controlled by sending two bytes. The + * first byte is the servo number xor'ed with 2: + * + * servo 0 = 2 + * servo 1 = 3 + * servo 2 = 0 + * servo 3 = 1 + * + * The second byte is the position. + */ + + buffer[0] = servo_no ^ 2; + buffer[1] = servo->pulse[servo_no]; + + dev_dbg(&servo->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]); + + retval = usb_control_msg(servo->udev, + usb_sndctrlpipe(servo->udev, 0), + 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2 * HZ); + if (retval != 2) + dev_err(&servo->udev->dev, "retval = %d\n", retval); + kfree(buffer); +} + +#define show_set(value) \ +static ssize_t set_servo##value (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + int degrees, minutes; \ + struct usb_interface *intf = to_usb_interface (dev); \ + struct phidget_servo *servo = usb_get_intfdata (intf); \ + \ + minutes = 0; \ + /* must at least convert degrees */ \ + if (sscanf (buf, "%d.%d", °rees, &minutes) < 1) { \ + return -EINVAL; \ + } \ + \ + if (degrees < -23 || degrees > (180 + 23) || \ + minutes < 0 || minutes > 59) { \ + return -EINVAL; \ + } \ + \ + if (servo->version >= 3) \ + change_position_v30 (servo, value, degrees, minutes); \ + else \ + change_position_v20 (servo, value, degrees, minutes); \ + \ + return count; \ +} \ + \ +static ssize_t show_servo##value (struct device *dev, char *buf) \ +{ \ + struct usb_interface *intf = to_usb_interface (dev); \ + struct phidget_servo *servo = usb_get_intfdata (intf); \ + \ + return sprintf (buf, "%d.%02d\n", servo->degrees[value], \ + servo->minutes[value]); \ +} \ +static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \ + show_servo##value, set_servo##value); + +show_set(0); +show_set(1); +show_set(2); +show_set(3); + +static int +servo_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct phidget_servo *dev = NULL; + + dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); + return -ENOMEM; + } + memset(dev, 0x00, sizeof (*dev)); + + dev->udev = usb_get_dev(udev); + switch (udev->descriptor.idVendor) { + case VENDOR_ID_WISEGROUP: + dev->version = 2; + break; + case VENDOR_ID_GLAB: + dev->version = 3; + break; + } + switch (udev->descriptor.idProduct) { + case DEVICE_ID_4MOTOR_SERVO_20: + case DEVICE_ID_4MOTOR_SERVO_30: + dev->quad_servo = 1; + break; + case DEVICE_ID_1MOTOR_SERVO_20: + case DEVICE_ID_1MOTOR_SERVO_30: + dev->quad_servo = 0; + break; + } + + usb_set_intfdata(interface, dev); + + device_create_file(&interface->dev, &dev_attr_servo0); + if (dev->quad_servo) { + device_create_file(&interface->dev, &dev_attr_servo1); + device_create_file(&interface->dev, &dev_attr_servo2); + device_create_file(&interface->dev, &dev_attr_servo3); + } + + dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n", + dev->quad_servo ? 4 : 1, dev->version); + if (dev->version == 2) + dev_info(&interface->dev, + "WARNING: v2.0 not tested! Please report if it works.\n"); + + return 0; +} + +static void +servo_disconnect(struct usb_interface *interface) +{ + struct phidget_servo *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + device_remove_file(&interface->dev, &dev_attr_servo0); + if (dev->quad_servo) { + device_remove_file(&interface->dev, &dev_attr_servo1); + device_remove_file(&interface->dev, &dev_attr_servo2); + device_remove_file(&interface->dev, &dev_attr_servo3); + } + + usb_put_dev(dev->udev); + + kfree(dev); + + dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n", + dev->quad_servo ? 4 : 1, dev->version); +} + +static struct usb_driver servo_driver = { + .owner = THIS_MODULE, + .name = "phidgetservo", + .probe = servo_probe, + .disconnect = servo_disconnect, + .id_table = id_table +}; + +static int __init +phidget_servo_init(void) +{ + int retval = 0; + + retval = usb_register(&servo_driver); + if (retval) + err("usb_register failed. Error number %d", retval); + + return retval; +} + +static void __exit +phidget_servo_exit(void) +{ + usb_deregister(&servo_driver); +} + +module_init(phidget_servo_init); +module_exit(phidget_servo_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c index f9609d060..d6e195820 100644 --- a/drivers/usb/misc/speedtch.c +++ b/drivers/usb/misc/speedtch.c @@ -269,7 +269,7 @@ struct udsl_instance_data { static void udsl_atm_dev_close (struct atm_dev *dev); static int udsl_atm_open (struct atm_vcc *vcc); static void udsl_atm_close (struct atm_vcc *vcc); -static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg); +static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void __user *arg); static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb); static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page); @@ -991,11 +991,11 @@ static void udsl_atm_close (struct atm_vcc *vcc) dbg ("udsl_atm_close successful"); } -static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) +static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void __user *arg) { switch (cmd) { case ATM_QUERYLOOP: - return put_user (ATM_LM_NONE, (int *) arg) ? -EFAULT : 0; + return put_user (ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index d705e815a..de9bf863e 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -672,7 +672,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) struct catc *catc = dev->priv; u32 cmd; - if (get_user(cmd, (u32 *)useraddr)) + if (get_user(cmd, (u32 __user *)useraddr)) return -EFAULT; switch (cmd) { @@ -726,7 +726,7 @@ static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { switch(cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void __user *)rq->ifr_data); + return netdev_ethtool_ioctl(dev, rq->ifr_data); default: return -EOPNOTSUPP; } diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c new file mode 100644 index 000000000..034ec2996 --- /dev/null +++ b/drivers/video/asiliantfb.c @@ -0,0 +1,620 @@ +/* + * drivers/video/asiliantfb.c + * frame buffer driver for Asiliant 69000 chip + * Copyright (C) 2001-2003 Saito.K & Jeanne + * + * from driver/video/chipsfb.c and, + * + * drivers/video/asiliantfb.c -- frame buffer device for + * Asiliant 69030 chip (formerly Intel, formerly Chips & Technologies) + * Author: apc@agelectronics.co.uk + * Copyright (C) 2000 AG Electronics + * Note: the data sheets don't seem to be available from Asiliant. + * They are available by searching developer.intel.com, but are not otherwise + * linked to. + * + * This driver should be portable with minimal effort to the 69000 display + * chip, and to the twin-display mode of the 69030. + * Contains code from Thomas Hhenleitner (thanks) + * + * Derived from the CT65550 driver chipsfb.c: + * Copyright (C) 1998 Paul Mackerras + * ...which was derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Built in clock of the 69030 */ +const unsigned Fref = 14318180; + +#define mmio_base (p->screen_base + 0x400000) + +#define mm_write_ind(num, val, ap, dp) do { \ + writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \ +} while (0) + +static void mm_write_xr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7ac, 0x7ad); +} +#define write_xr(num, val) mm_write_xr(p, num, val) + +static void mm_write_fr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7a0, 0x7a1); +} +#define write_fr(num, val) mm_write_fr(p, num, val) + +static void mm_write_cr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x7a8, 0x7a9); +} +#define write_cr(num, val) mm_write_cr(p, num, val) + +static void mm_write_gr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x79c, 0x79d); +} +#define write_gr(num, val) mm_write_gr(p, num, val) + +static void mm_write_sr(struct fb_info *p, u8 reg, u8 data) +{ + mm_write_ind(reg, data, 0x788, 0x789); +} +#define write_sr(num, val) mm_write_sr(p, num, val) + +static void mm_write_ar(struct fb_info *p, u8 reg, u8 data) +{ + readb(mmio_base + 0x7b4); + mm_write_ind(reg, data, 0x780, 0x780); +} +#define write_ar(num, val) mm_write_ar(p, num, val) + +/* + * Exported functions + */ +int asiliantfb_init(void); + +static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *); +static int asiliantfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int asiliantfb_set_par(struct fb_info *info); +static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); + +static struct fb_ops asiliantfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = asiliantfb_check_var, + .fb_set_par = asiliantfb_set_par, + .fb_setcolreg = asiliantfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + +/* Calculate the ratios for the dot clocks without using a single long long + * value */ +static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div) +{ + unsigned pixclock = *ppixclock; + unsigned Ftarget = 1000000 * (1000000 / pixclock); + unsigned n; + unsigned best_error = 0xffffffff; + unsigned best_m = 0xffffffff, + best_n = 0xffffffff; + unsigned ratio; + unsigned remainder; + unsigned char divisor = 0; + + /* Calculate the frequency required. This is hard enough. */ + ratio = 1000000 / pixclock; + remainder = 1000000 % pixclock; + Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock; + + while (Ftarget < 100000000) { + divisor += 0x10; + Ftarget <<= 1; + } + + ratio = Ftarget / Fref; + remainder = Ftarget % Fref; + + /* This expresses the constraint that 150kHz <= Fref/n <= 5Mhz, + * together with 3 <= n <= 257. */ + for (n = 3; n <= 257; n++) { + unsigned m = n * ratio + (n * remainder) / Fref; + + /* 3 <= m <= 257 */ + if (m >= 3 && m <= 257) { + unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ? + ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n)); + if (new_error < best_error) { + best_n = n; + best_m = m; + best_error = new_error; + } + } + /* But if VLD = 4, then 4m <= 1028 */ + else if (m <= 1028) { + /* remember there are still only 8-bits of precision in m, so + * avoid over-optimistic error calculations */ + unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ? + ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n)); + if (new_error < best_error) { + best_n = n; + best_m = m; + best_error = new_error; + } + } + } + if (best_m > 257) + best_m >>= 2; /* divide m by 4, and leave VCO loop divide at 4 */ + else + divisor |= 4; /* or set VCO loop divide to 1 */ + *dclk2_m = best_m - 2; + *dclk2_n = best_n - 2; + *dclk2_div = divisor; + *ppixclock = pixclock; + return; +} + +static void asiliant_set_timing(struct fb_info *p) +{ + unsigned hd = p->var.xres / 8; + unsigned hs = (p->var.xres + p->var.right_margin) / 8; + unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8; + unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8; + unsigned vd = p->var.yres; + unsigned vs = p->var.yres + p->var.lower_margin; + unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len; + unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len; + unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8; + + if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) { + write_fr(0x01, 0x02); /* LCD */ + } else { + write_fr(0x01, 0x01); /* CRT */ + } + + write_cr(0x11, (ve - 1) & 0x0f); + write_cr(0x00, (ht - 5) & 0xff); + write_cr(0x01, hd - 1); + write_cr(0x02, hd); + write_cr(0x03, ((ht - 1) & 0x1f) | 0x80); + write_cr(0x04, hs); + write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f)); + write_cr(0x3c, (ht - 1) & 0xc0); + write_cr(0x06, (vt - 2) & 0xff); + write_cr(0x30, (vt - 2) >> 8); + write_cr(0x07, 0x00); + write_cr(0x08, 0x00); + write_cr(0x09, 0x00); + write_cr(0x10, (vs - 1) & 0xff); + write_cr(0x32, ((vs - 1) >> 8) & 0xf); + write_cr(0x11, ((ve - 1) & 0x0f) | 0x80); + write_cr(0x12, (vd - 1) & 0xff); + write_cr(0x31, ((vd - 1) & 0xf00) >> 8); + write_cr(0x13, wd & 0xff); + write_cr(0x41, (wd & 0xf00) >> 8); + write_cr(0x15, (vs - 1) & 0xff); + write_cr(0x33, ((vs - 1) >> 8) & 0xf); + write_cr(0x38, ((ht - 5) & 0x100) >> 8); + write_cr(0x16, (vt - 1) & 0xff); + write_cr(0x18, 0x00); + + if (p->var.xres == 640) { + writeb(0xc7, mmio_base + 0x784); /* set misc output reg */ + } else { + writeb(0x07, mmio_base + 0x784); /* set misc output reg */ + } +} + +static int asiliantfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *p) +{ + unsigned long Ftarget, ratio, remainder; + + ratio = 1000000 / var->pixclock; + remainder = 1000000 % var->pixclock; + Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock; + + /* First check the constraint that the maximum post-VCO divisor is 32, + * and the maximum Fvco is 220MHz */ + if (Ftarget > 220000000 || Ftarget < 3125000) { + printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n"); + return -ENXIO; + } + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + + if (var->bits_per_pixel == 24) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->blue.length = var->green.length = 8; + } else if (var->bits_per_pixel == 16) { + switch (var->red.offset) { + case 11: + var->green.length = 6; + break; + case 10: + var->green.length = 5; + break; + default: + return -EINVAL; + } + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = var->blue.length = 5; + } else if (var->bits_per_pixel == 8) { + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + } + return 0; +} + +static int asiliantfb_set_par(struct fb_info *p) +{ + u8 dclk2_m; /* Holds m-2 value for register */ + u8 dclk2_n; /* Holds n-2 value for register */ + u8 dclk2_div; /* Holds divisor bitmask */ + + /* Set pixclock */ + asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div); + + /* Set color depth */ + if (p->var.bits_per_pixel == 24) { + write_xr(0x81, 0x16); /* 24 bit packed color mode */ + write_xr(0x82, 0x00); /* Disable palettes */ + write_xr(0x20, 0x20); /* 24 bit blitter mode */ + } else if (p->var.bits_per_pixel == 16) { + if (p->var.red.offset == 11) + write_xr(0x81, 0x15); /* 16 bit color mode */ + else + write_xr(0x81, 0x14); /* 15 bit color mode */ + write_xr(0x82, 0x00); /* Disable palettes */ + write_xr(0x20, 0x10); /* 16 bit blitter mode */ + } else if (p->var.bits_per_pixel == 8) { + write_xr(0x0a, 0x02); /* Linear */ + write_xr(0x81, 0x12); /* 8 bit color mode */ + write_xr(0x82, 0x00); /* Graphics gamma enable */ + write_xr(0x20, 0x00); /* 8 bit blitter mode */ + } + p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3); + p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + write_xr(0xc4, dclk2_m); + write_xr(0xc5, dclk2_n); + write_xr(0xc7, dclk2_div); + /* Set up the CR registers */ + asiliant_set_timing(p); + return 0; +} + +static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *p) +{ + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + /* Set hardware palete */ + writeb(regno, mmio_base + 0x790); + udelay(1); + writeb(red, mmio_base + 0x791); + writeb(green, mmio_base + 0x791); + writeb(blue, mmio_base + 0x791); + + switch(p->var.bits_per_pixel) { + case 15: + if (regno < 16) { + ((u32 *)(p->pseudo_palette))[regno] = + ((red & 0xf8) << 7) | + ((green & 0xf8) << 2) | + ((blue & 0xf8) >> 3); + } + break; + case 16: + if (regno < 16) { + ((u32 *)(p->pseudo_palette))[regno] = + ((red & 0xf8) << 8) | + ((green & 0xfc) << 3) | + ((blue & 0xf8) >> 3); + } + break; + case 24: + if (regno < 24) { + ((u32 *)(p->pseudo_palette))[regno] = + (red << 16) | + (green << 8) | + (blue); + } + break; + } + return 0; +} + +struct chips_init_reg { + unsigned char addr; + unsigned char data; +}; + +#define N_ELTS(x) (sizeof(x) / sizeof(x[0])) + +static struct chips_init_reg chips_init_sr[] = +{ + {0x00, 0x03}, /* Reset register */ + {0x01, 0x01}, /* Clocking mode */ + {0x02, 0x0f}, /* Plane mask */ + {0x04, 0x0e} /* Memory mode */ +}; + +static struct chips_init_reg chips_init_gr[] = +{ + {0x03, 0x00}, /* Data rotate */ + {0x05, 0x00}, /* Graphics mode */ + {0x06, 0x01}, /* Miscellaneous */ + {0x08, 0x00} /* Bit mask */ +}; + +static struct chips_init_reg chips_init_ar[] = +{ + {0x10, 0x01}, /* Mode control */ + {0x11, 0x00}, /* Overscan */ + {0x12, 0x0f}, /* Memory plane enable */ + {0x13, 0x00} /* Horizontal pixel panning */ +}; + +static struct chips_init_reg chips_init_cr[] = +{ + {0x0c, 0x00}, /* Start address high */ + {0x0d, 0x00}, /* Start address low */ + {0x40, 0x00}, /* Extended Start Address */ + {0x41, 0x00}, /* Extended Start Address */ + {0x14, 0x00}, /* Underline location */ + {0x17, 0xe3}, /* CRT mode control */ + {0x70, 0x00} /* Interlace control */ +}; + + +static struct chips_init_reg chips_init_fr[] = +{ + {0x01, 0x02}, + {0x03, 0x08}, + {0x08, 0xcc}, + {0x0a, 0x08}, + {0x18, 0x00}, + {0x1e, 0x80}, + {0x40, 0x83}, + {0x41, 0x00}, + {0x48, 0x13}, + {0x4d, 0x60}, + {0x4e, 0x0f}, + + {0x0b, 0x01}, + + {0x21, 0x51}, + {0x22, 0x1d}, + {0x23, 0x5f}, + {0x20, 0x4f}, + {0x34, 0x00}, + {0x24, 0x51}, + {0x25, 0x00}, + {0x27, 0x0b}, + {0x26, 0x00}, + {0x37, 0x80}, + {0x33, 0x0b}, + {0x35, 0x11}, + {0x36, 0x02}, + {0x31, 0xea}, + {0x32, 0x0c}, + {0x30, 0xdf}, + {0x10, 0x0c}, + {0x11, 0xe0}, + {0x12, 0x50}, + {0x13, 0x00}, + {0x16, 0x03}, + {0x17, 0xbd}, + {0x1a, 0x00}, +}; + + +static struct chips_init_reg chips_init_xr[] = +{ + {0xce, 0x00}, /* set default memory clock */ + {0xcc, 200 }, /* MCLK ratio M */ + {0xcd, 18 }, /* MCLK ratio N */ + {0xce, 0x90}, /* MCLK divisor = 2 */ + + {0xc4, 209 }, + {0xc5, 118 }, + {0xc7, 32 }, + {0xcf, 0x06}, + {0x09, 0x01}, /* IO Control - CRT controller extensions */ + {0x0a, 0x02}, /* Frame buffer mapping */ + {0x0b, 0x01}, /* PCI burst write */ + {0x40, 0x03}, /* Memory access control */ + {0x80, 0x82}, /* Pixel pipeline configuration 0 */ + {0x81, 0x12}, /* Pixel pipeline configuration 1 */ + {0x82, 0x08}, /* Pixel pipeline configuration 2 */ + + {0xd0, 0x0f}, + {0xd1, 0x01}, +}; + +static void __init chips_hw_init(struct fb_info *p) +{ + int i; + + for (i = 0; i < N_ELTS(chips_init_xr); ++i) + write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); + write_xr(0x81, 0x12); + write_xr(0x82, 0x08); + write_xr(0x20, 0x00); + for (i = 0; i < N_ELTS(chips_init_sr); ++i) + write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); + for (i = 0; i < N_ELTS(chips_init_gr); ++i) + write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); + for (i = 0; i < N_ELTS(chips_init_ar); ++i) + write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); + /* Enable video output in attribute index register */ + writeb(0x20, mmio_base + 0x780); + for (i = 0; i < N_ELTS(chips_init_cr); ++i) + write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); + for (i = 0; i < N_ELTS(chips_init_fr); ++i) + write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); +} + +static struct fb_fix_screeninfo asiliantfb_fix __initdata = { + .id = "Asiliant 69000", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, + .line_length = 640, + .smem_len = 0x200000, /* 2MB */ +}; + +static struct fb_var_screeninfo asiliantfb_var __initdata = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, + .pixclock = 39722, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 33, + .lower_margin = 10, + .hsync_len = 96, + .vsync_len = 2, +}; + +static void __init init_asiliant(struct fb_info *p, unsigned long addr) +{ + p->fix = asiliantfb_fix; + p->fix.smem_start = addr; + p->var = asiliantfb_var; + p->fbops = &asiliantfb_ops; + p->flags = FBINFO_FLAG_DEFAULT; + + fb_alloc_cmap(&p->cmap, 256, 0); + + if (register_framebuffer(p) < 0) { + printk(KERN_ERR "C&T 69000 framebuffer failed to register\n"); + return; + } + + printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n", + p->node, p->fix.smem_len / 1024); + + writeb(0xff, mmio_base + 0x78c); + chips_hw_init(p); +} + +static int __devinit +asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) +{ + unsigned long addr, size; + struct fb_info *p; + + if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) + return -ENODEV; + addr = pci_resource_start(dp, 0); + size = pci_resource_len(dp, 0); + if (addr == 0) + return -ENODEV; + if (!request_mem_region(addr, size, "asiliantfb")) + return -EBUSY; + + p = framebuffer_alloc(sizeof(u32) * 256, &dp->dev); + if (!p) { + release_mem_region(addr, size); + return -ENOMEM; + } + p->pseudo_palette = p->par; + p->par = NULL; + + p->screen_base = ioremap(addr, 0x800000); + if (p->screen_base == NULL) { + release_mem_region(addr, size); + framebuffer_release(p); + return -ENOMEM; + } + + pci_write_config_dword(dp, 4, 0x02800083); + writeb(3, addr + 0x400784); + + init_asiliant(p, addr); + + /* Clear the entire framebuffer */ + memset(p->screen_base, 0, 0x200000); + + pci_set_drvdata(dp, p); + return 0; +} + +static void __devexit asiliantfb_remove(struct pci_dev *dp) +{ + struct fb_info *p = pci_get_drvdata(dp); + + unregister_framebuffer(p); + iounmap(p->screen_base); + release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); + pci_set_drvdata(dp, NULL); + framebuffer_release(p); +} + +static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl); + +static struct pci_driver asiliantfb_driver = { + .name = "asiliantfb", + .id_table = asiliantfb_pci_tbl, + .probe = asiliantfb_pci_init, + .remove = __devexit_p(asiliantfb_remove), +}; + +int __init asiliantfb_init(void) +{ + return pci_module_init(&asiliantfb_driver); +} + +static void __exit asiliantfb_exit(void) +{ + pci_unregister_driver(&asiliantfb_driver); +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c new file mode 100644 index 000000000..2afc4148b --- /dev/null +++ b/drivers/video/gbefb.c @@ -0,0 +1,1200 @@ +/* + * SGI GBE frame buffer driver + * + * Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist + * Copyright (C) 2002 Vivien Chappelier + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86 +#include +#endif +#ifdef CONFIG_MIPS +#include +#endif +#include +#include +#include + +#include