diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 13:15:58 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 13:15:58 -0700 |
commit | 467cbd207abdbfe29514b5804a22661ab6e80dc6 (patch) | |
tree | 026a03bfcb0f755c5d61fcf288d98582ebd55093 | |
parent | 7125764c5d1a5c72d522f1011b6cc8b8100b48fe (diff) | |
parent | b5660ba76b41af69a0c09d434927bb4b4cadd4b1 (diff) |
Merge branch 'x86-nuke-platforms-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 old platform removal from Peter Anvin:
"This patchset removes support for several completely obsolete
platforms, where the maintainers either have completely vanished or
acked the removal. For some of them it is questionable if there even
exists functional specimens of the hardware"
Geert Uytterhoeven apparently thought this was a April Fool's pull request ;)
* 'x86-nuke-platforms-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, platforms: Remove NUMAQ
x86, platforms: Remove SGI Visual Workstation
x86, apic: Remove support for IBM Summit/EXA chipset
x86, apic: Remove support for ia32-based Unisys ES7000
47 files changed, 15 insertions, 8806 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 07de7e19b4c..27e67a98b7b 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -413,8 +413,6 @@ serial-console.txt - how to set up Linux with a serial line console as the default. sgi-ioc4.txt - description of the SGI IOC4 PCI (multi function) device. -sgi-visws.txt - - short blurb on the SGI Visual Workstations. sh/ - directory with info on porting Linux to a new architecture. smsc_ece1099.txt diff --git a/Documentation/sgi-visws.txt b/Documentation/sgi-visws.txt deleted file mode 100644 index 7ff0811ca2b..00000000000 --- a/Documentation/sgi-visws.txt +++ /dev/null @@ -1,13 +0,0 @@ - -The SGI Visual Workstations (models 320 and 540) are based around -the Cobalt, Lithium, and Arsenic ASICs. The Cobalt ASIC is the -main system ASIC which interfaces the 1-4 IA32 cpus, the memory -system, and the I/O system in the Lithium ASIC. The Cobalt ASIC -also contains the 3D gfx rendering engine which renders to main -system memory -- part of which is used as the frame buffer which -is DMA'ed to a video connector using the Arsenic ASIC. A PIIX4 -chip and NS87307 are used to provide legacy device support (IDE, -serial, floppy, and parallel). - -The Visual Workstation chipset largely conforms to the PC architecture -with some notable exceptions such as interrupt handling. diff --git a/Documentation/sound/oss/vwsnd b/Documentation/sound/oss/vwsnd deleted file mode 100644 index 4c6cbdb3c54..00000000000 --- a/Documentation/sound/oss/vwsnd +++ /dev/null @@ -1,293 +0,0 @@ -vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual -Workstations' onboard audio. - -Copyright 1999 Silicon Graphics, Inc. All rights reserved. - - -At the time of this writing, March 1999, there are two models of -Visual Workstation, the 320 and the 540. This document only describes -those models. Future Visual Workstation models may have different -sound capabilities, and this driver will probably not work on those -boxes. - -The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio -codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also -known as Lithium. This driver programs both chips. - -============================================================================== -QUICK CONFIGURATION - - # insmod soundcore - # insmod vwsnd - -============================================================================== -I/O CONNECTIONS - -On the Visual Workstation, only three of the AD1843 inputs are hooked -up. The analog line in jacks are connected to the AD1843's AUX1 -input. The CD audio lines are connected to the AD1843's AUX2 input. -The microphone jack is connected to the AD1843's MIC input. The mic -jack is mono, but the signal is delivered to both the left and right -MIC inputs. You can record in stereo from the mic input, but you will -get the same signal on both channels (within the limits of A/D -accuracy). Full scale on the Line input is +/- 2.0 V. Full scale on -the MIC input is 20 dB less, or +/- 0.2 V. - -The AD1843's LOUT1 outputs are connected to the Line Out jacks. The -AD1843's HPOUT outputs are connected to the speaker/headphone jack. -LOUT2 is not connected. Line out's maximum level is +/- 2.0 V peak to -peak. The speaker/headphone out's maximum is +/- 4.0 V peak to peak. - -The AD1843's PCM input channel and one of its output channels (DAC1) -are connected to Lithium. The other output channel (DAC2) is not -connected. - -============================================================================== -CAPABILITIES - -The AD1843 has PCM input and output (Pulse Code Modulation, also known -as wavetable). PCM input and output can be mono or stereo in any of -four formats. The formats are 16 bit signed and 8 bit unsigned, -u-Law, and A-Law format. Any sample rate from 4 KHz to 49 KHz is -available, in 1 Hz increments. - -The AD1843 includes an analog mixer that can mix all three input -signals (line, mic and CD) into the analog outputs. The mixer has a -separate gain control and mute switch for each input. - -There are two outputs, line out and speaker/headphone out. They -always produce the same signal, and the speaker always has 3 dB more -gain than the line out. The speaker/headphone output can be muted, -but this driver does not export that function. - -The hardware can sync audio to the video clock, but this driver does -not have a way to specify syncing to video. - -============================================================================== -PROGRAMMING - -This section explains the API supported by the driver. Also see the -Open Sound Programming Guide at http://www.opensound.com/pguide/ . -This section assumes familiarity with that document. - -The driver has two interfaces, an I/O interface and a mixer interface. -There is no MIDI or sequencer capability. - -============================================================================== -PROGRAMMING PCM I/O - -The I/O interface is usually accessed as /dev/audio or /dev/dsp. -Using the standard Open Sound System (OSS) ioctl calls, the sample -rate, number of channels, and sample format may be set within the -limitations described above. The driver supports triggering. It also -supports getting the input and output pointers with one-sample -accuracy. - -The SNDCTL_DSP_GETCAP ioctl returns these capabilities. - - DSP_CAP_DUPLEX - driver supports full duplex. - - DSP_CAP_TRIGGER - driver supports triggering. - - DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR - and SNDCTL_DSP_GETOPTR are accurate to a few samples. - -Memory mapping (mmap) is not implemented. - -The driver permits subdivided fragment sizes from 64 to 4096 bytes. -The number of fragments can be anything from 3 fragments to however -many fragments fit into 124 kilobytes. It is up to the user to -determine how few/small fragments can be used without introducing -glitches with a given workload. Linux is not realtime, so we can't -promise anything. (sigh...) - -When this driver is switched into or out of mu-Law or A-Law mode on -output, it may produce an audible click. This is unavoidable. To -prevent clicking, use signed 16-bit mode instead, and convert from -mu-Law or A-Law format in software. - -============================================================================== -PROGRAMMING THE MIXER INTERFACE - -The mixer interface is usually accessed as /dev/mixer. It is accessed -through ioctls. The mixer allows the application to control gain or -mute several audio signal paths, and also allows selection of the -recording source. - -Each of the constants described here can be read using the -MIXER_READ(SOUND_MIXER_xxx) ioctl. Those that are not read-only can -also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl. In most -cases, <sys/soundcard.h> defines constants SOUND_MIXER_READ_xxx and -SOUND_MIXER_WRITE_xxx which work just as well. - -SOUND_MIXER_CAPS Read-only - -This is a mask of optional driver capabilities that are implemented. -This driver's only capability is SOUND_CAP_EXCL_INPUT, which means -that only one recording source can be active at a time. - -SOUND_MIXER_DEVMASK Read-only - -This is a mask of the sound channels. This driver's channels are PCM, -LINE, MIC, CD, and RECLEV. - -SOUND_MIXER_STEREODEVS Read-only - -This is a mask of which sound channels are capable of stereo. All -channels are capable of stereo. (But see caveat on MIC input in I/O -CONNECTIONS section above). - -SOUND_MIXER_OUTMASK Read-only - -This is a mask of channels that route inputs through to outputs. -Those are LINE, MIC, and CD. - -SOUND_MIXER_RECMASK Read-only - -This is a mask of channels that can be recording sources. Those are -PCM, LINE, MIC, CD. - -SOUND_MIXER_PCM Default: 0x5757 (0 dB) - -This is the gain control for PCM output. The left and right channel -gain are controlled independently. This gain control has 64 levels, -which range from -82.5 dB to +12.0 dB in 1.5 dB steps. Those 64 -levels are mapped onto 100 levels at the ioctl, see below. - -SOUND_MIXER_LINE Default: 0x4a4a (0 dB) - -This is the gain control for mixing the Line In source into the -outputs. The left and right channel gain are controlled -independently. This gain control has 32 levels, which range from --34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto -100 levels at the ioctl, see below. - -SOUND_MIXER_MIC Default: 0x4a4a (0 dB) - -This is the gain control for mixing the MIC source into the outputs. -The left and right channel gain are controlled independently. This -gain control has 32 levels, which range from -34.5 dB to +12.0 dB in -1.5 dB steps. Those 32 levels are mapped onto 100 levels at the -ioctl, see below. - -SOUND_MIXER_CD Default: 0x4a4a (0 dB) - -This is the gain control for mixing the CD audio source into the -outputs. The left and right channel gain are controlled -independently. This gain control has 32 levels, which range from --34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto -100 levels at the ioctl, see below. - -SOUND_MIXER_RECLEV Default: 0 (0 dB) - -This is the gain control for PCM input (RECording LEVel). The left -and right channel gain are controlled independently. This gain -control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB -steps. Those 16 levels are mapped onto 100 levels at the ioctl, see -below. - -SOUND_MIXER_RECSRC Default: SOUND_MASK_LINE - -This is a mask of currently selected PCM input sources (RECording -SouRCes). Because the AD1843 can only have a single recording source -at a time, only one bit at a time can be set in this mask. The -allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC, -or SOUND_MASK_CD. Selecting SOUND_MASK_PCM sets up internal -resampling which is useful for loopback testing and for hardware -sample rate conversion. But software sample rate conversion is -probably faster, so I don't know how useful that is. - -SOUND_MIXER_OUTSRC DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD - -This is a mask of sources that are currently passed through to the -outputs. Those sources whose bits are not set are muted. - -============================================================================== -GAIN CONTROL - -There are five gain controls listed above. Each has 16, 32, or 64 -steps. Each control has 1.5 dB of gain per step. Each control is -stereo. - -The OSS defines the argument to a channel gain ioctl as having two -components, left and right, each of which ranges from 0 to 100. The -two components are packed into the same word, with the left side gain -in the least significant byte, and the right side gain in the second -least significant byte. In C, we would say this. - - #include <assert.h> - - ... - - assert(leftgain >= 0 && leftgain <= 100); - assert(rightgain >= 0 && rightgain <= 100); - arg = leftgain | rightgain << 8; - -So each OSS gain control has 101 steps. But the hardware has 16, 32, -or 64 steps. The hardware steps are spread across the 101 OSS steps -nearly evenly. The conversion formulas are like this, given N equals -16, 32, or 64. - - int round = N/2 - 1; - OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1); - hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100; - -Here is a snippet of C code that will return the left and right gain -of any channel in dB. Pass it one of the predefined gain_desc_t -structures to access any of the five channels' gains. - - typedef struct gain_desc { - float min_gain; - float gain_step; - int nbits; - int chan; - } gain_desc_t; - - const gain_desc_t gain_pcm = { -82.5, 1.5, 6, SOUND_MIXER_PCM }; - const gain_desc_t gain_line = { -34.5, 1.5, 5, SOUND_MIXER_LINE }; - const gain_desc_t gain_mic = { -34.5, 1.5, 5, SOUND_MIXER_MIC }; - const gain_desc_t gain_cd = { -34.5, 1.5, 5, SOUND_MIXER_CD }; - const gain_desc_t gain_reclev = { 0.0, 1.5, 4, SOUND_MIXER_RECLEV }; - - int get_gain_dB(int fd, const gain_desc_t *gp, - float *left, float *right) - { - int word; - int lg, rg; - int mask = (1 << gp->nbits) - 1; - - if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0) - return -1; /* fail */ - lg = word & 0xFF; - rg = word >> 8 & 0xFF; - lg = (lg * mask + mask / 2) / 100; - rg = (rg * mask + mask / 2) / 100; - *left = gp->min_gain + gp->gain_step * lg; - *right = gp->min_gain + gp->gain_step * rg; - return 0; - } - -And here is the corresponding routine to set a channel's gain in dB. - - int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right) - { - float max_gain = - gp->min_gain + (1 << gp->nbits) * gp->gain_step; - float round = gp->gain_step / 2; - int mask = (1 << gp->nbits) - 1; - int word; - int lg, rg; - - if (left < gp->min_gain || right < gp->min_gain) - return EINVAL; - lg = (left - gp->min_gain + round) / gp->gain_step; - rg = (right - gp->min_gain + round) / gp->gain_step; - if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits)) - return EINVAL; - lg = (100 * lg + mask / 2) / mask; - rg = (100 * rg + mask / 2) / mask; - word = lg | rg << 8; - - return ioctl(fd, MIXER_WRITE(gp->chan), &word); - } - diff --git a/MAINTAINERS b/MAINTAINERS index c1b982cd52d..b99bbbc4c5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7840,13 +7840,6 @@ F: Documentation/ia64/serial.txt F: drivers/tty/serial/ioc?_serial.c F: include/linux/ioc?.h -SGI VISUAL WORKSTATION 320 AND 540 -M: Andrey Panin <pazke@donpac.ru> -L: linux-visws-devel@lists.sf.net -W: http://linux-visws.sf.net -S: Maintained for 2.6. -F: Documentation/sgi-visws.txt - SGI XP/XPC/XPNET DRIVER M: Cliff Whickman <cpw@sgi.com> M: Robin Holt <robinmholt@gmail.com> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ac04d980439..f7307174297 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -344,12 +344,9 @@ config X86_EXTENDED_PLATFORM for the following (non-PC) 32 bit x86 platforms: Goldfish (Android emulator) AMD Elan - NUMAQ (IBM/Sequent) RDC R-321x SoC SGI 320/540 (Visual Workstation) STA2X11-based (e.g. Northville) - Summit/EXA (IBM x440) - Unisys ES7000 IA32 series Moorestown MID devices If you have one of these systems, or if you want to build a @@ -487,49 +484,22 @@ config X86_32_NON_STANDARD depends on X86_32 && SMP depends on X86_EXTENDED_PLATFORM ---help--- - This option compiles in the NUMAQ, Summit, bigsmp, ES7000, - STA2X11, default subarchitectures. It is intended for a generic - binary kernel. If you select them all, kernel will probe it - one by one and will fallback to default. + This option compiles in the bigsmp and STA2X11 default + subarchitectures. It is intended for a generic binary + kernel. If you select them all, kernel will probe it one by + one and will fallback to default. # Alphabetically sorted list of Non standard 32 bit platforms -config X86_NUMAQ - bool "NUMAQ (IBM/Sequent)" - depends on X86_32_NON_STANDARD - depends on PCI - select NUMA - select X86_MPPARSE - ---help--- - This option is used for getting Linux to run on a NUMAQ (IBM/Sequent) - NUMA multiquad box. This changes the way that processors are - bootstrapped, and uses Clustered Logical APIC addressing mode instead - of Flat Logical. You will need a new lynxer.elf file to flash your - firmware with - send email to <Martin.Bligh@us.ibm.com>. - config X86_SUPPORTS_MEMORY_FAILURE def_bool y # MCE code calls memory_failure(): depends on X86_MCE # On 32-bit this adds too big of NODES_SHIFT and we run out of page flags: - depends on !X86_NUMAQ # On 32-bit SPARSEMEM adds too big of SECTIONS_WIDTH: depends on X86_64 || !SPARSEMEM select ARCH_SUPPORTS_MEMORY_FAILURE -config X86_VISWS - bool "SGI 320/540 (Visual Workstation)" - depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT - depends on X86_32_NON_STANDARD - ---help--- - The SGI Visual Workstation series is an IA32-based workstation - based on SGI systems chips with some legacy PC hardware attached. - - Say Y here to create a kernel to run on the SGI 320 or 540. - - A kernel compiled for the Visual Workstation will run on general - PCs as well. See <file:Documentation/sgi-visws.txt> for details. - config STA2X11 bool "STA2X11 Companion Chip Support" depends on X86_32_NON_STANDARD && PCI @@ -546,20 +516,6 @@ config STA2X11 option is selected the kernel will still be able to boot on standard PC machines. -config X86_SUMMIT - bool "Summit/EXA (IBM x440)" - depends on X86_32_NON_STANDARD - ---help--- - This option is needed for IBM systems that use the Summit/EXA chipset. - In particular, it is needed for the x440. - -config X86_ES7000 - bool "Unisys ES7000 IA32 series" - depends on X86_32_NON_STANDARD && X86_BIGSMP - ---help--- - Support for Unisys ES7000 systems. Say 'Y' here if this kernel is - supposed to run on an IA32-based Unisys ES7000 system. - config X86_32_IRIS tristate "Eurobraille/Iris poweroff module" depends on X86_32 @@ -682,14 +638,6 @@ config MEMTEST memtest=4, mean do 4 test patterns. If you are unsure how to answer this question, answer N. -config X86_SUMMIT_NUMA - def_bool y - depends on X86_32 && NUMA && X86_32_NON_STANDARD - -config X86_CYCLONE_TIMER - def_bool y - depends on X86_SUMMIT - source "arch/x86/Kconfig.cpu" config HPET_TIMER @@ -818,7 +766,7 @@ config NR_CPUS range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64 default "1" if !SMP default "8192" if MAXSMP - default "32" if SMP && (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000) + default "32" if SMP && X86_BIGSMP default "8" if SMP ---help--- This allows you to specify the maximum number of CPUs which this @@ -882,10 +830,6 @@ config X86_IO_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI -config X86_VISWS_APIC - def_bool y - depends on X86_32 && X86_VISWS - config X86_REROUTE_FOR_BROKEN_BOOT_IRQS bool "Reroute for broken boot IRQs" depends on X86_IO_APIC @@ -1103,13 +1047,11 @@ config X86_CPUID choice prompt "High Memory Support" - default HIGHMEM64G if X86_NUMAQ default HIGHMEM4G depends on X86_32 config NOHIGHMEM bool "off" - depends on !X86_NUMAQ ---help--- Linux can use up to 64 Gigabytes of physical memory on x86 systems. However, the address space of 32-bit x86 processors is only 4 @@ -1146,7 +1088,6 @@ config NOHIGHMEM config HIGHMEM4G bool "4GB" - depends on !X86_NUMAQ ---help--- Select this if you have a 32-bit processor and between 1 and 4 gigabytes of physical RAM. @@ -1238,8 +1179,8 @@ config DIRECT_GBPAGES config NUMA bool "Numa Memory Allocation and Scheduler Support" depends on SMP - depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI)) - default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP) + depends on X86_64 || (X86_32 && HIGHMEM64G && X86_BIGSMP) + default y if X86_BIGSMP ---help--- Enable NUMA (Non Uniform Memory Access) support. @@ -1250,15 +1191,11 @@ config NUMA For 64-bit this is recommended if the system is Intel Core i7 (or later), AMD Opteron, or EM64T NUMA. - For 32-bit this is only needed on (rare) 32-bit-only platforms - that support NUMA topologies, such as NUMAQ / Summit, or if you - boot a 32-bit kernel on a 64-bit NUMA platform. + For 32-bit this is only needed if you boot a 32-bit + kernel on a 64-bit NUMA platform. Otherwise, you should say N. -comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" - depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI) - config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" @@ -1300,7 +1237,6 @@ config NODES_SHIFT range 1 10 default "10" if MAXSMP default "6" if X86_64 - default "4" if X86_NUMAQ default "3" depends on NEED_MULTIPLE_NODES ---help--- diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index f3aaf231b4e..6983314c8b3 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -359,7 +359,7 @@ config X86_P6_NOP config X86_TSC def_bool y - depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) && !X86_NUMAQ) || X86_64 + depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64 config X86_CMPXCHG64 def_bool y diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 2377f5618fb..8dcd35c4c78 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -90,12 +90,6 @@ enum fixed_addresses { FIX_IO_APIC_BASE_0, FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1, #endif -#ifdef CONFIG_X86_VISWS_APIC - FIX_CO_CPU, /* Cobalt timer */ - FIX_CO_APIC, /* Cobalt APIC Redirection Table */ - FIX_LI_PCIA, /* Lithium PCI Bridge A */ - FIX_LI_PCIB, /* Lithium PCI Bridge B */ -#endif FIX_RO_IDT, /* Virtual mapping for read-only IDT */ #ifdef CONFIG_X86_32 FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 67d69b8e2d2..a307b7530e5 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -98,7 +98,6 @@ extern void trace_call_function_single_interrupt(void); #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs)) extern unsigned long io_apic_irqs; -extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); extern void disable_IO_APIC(void); diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 8a9b3e288cb..1ec990bd7dc 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -11,9 +11,6 @@ #ifdef CONFIG_NUMA extern struct pglist_data *node_data[]; #define NODE_DATA(nid) (node_data[nid]) - -#include <asm/numaq.h> - #endif /* CONFIG_NUMA */ #ifdef CONFIG_DISCONTIGMEM diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h index 3e6b4920ef5..f5a61795673 100644 --- a/arch/x86/include/asm/mpspec.h +++ b/arch/x86/include/asm/mpspec.h @@ -25,12 +25,6 @@ extern int pic_mode; extern unsigned int def_to_bigsmp; -#ifdef CONFIG_X86_NUMAQ -extern int mp_bus_id_to_node[MAX_MP_BUSSES]; -extern int mp_bus_id_to_local[MAX_MP_BUSSES]; -extern int quad_local_to_mp_bus_id [NR_CPUS/4][4]; -#endif - #else /* CONFIG_X86_64: */ #define MAX_MP_BUSSES 256 diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h deleted file mode 100644 index c3b3c322fd8..00000000000 --- a/arch/x86/include/asm/numaq.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Written by: Patricia Gaughen, IBM Corporation - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gone@us.ibm.com> - */ - -#ifndef _ASM_X86_NUMAQ_H -#define _ASM_X86_NUMAQ_H - -#ifdef CONFIG_X86_NUMAQ - -extern int found_numaq; -extern int numaq_numa_init(void); -extern int pci_numaq_init(void); - -extern void *xquad_portio; - -#define XQUAD_PORTIO_BASE 0xfe400000 -#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ -#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) - -/* - * SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the - */ -#define SYS_CFG_DATA_PRIV_ADDR 0x0009d000 /* place for scd in private - quad space */ - -/* - * Communication area for each processor on lynxer-processor tests. - * - * NOTE: If you change the size of this eachproc structure you need - * to change the definition for EACH_QUAD_SIZE. - */ -struct eachquadmem { - unsigned int priv_mem_start; /* Starting address of this */ - /* quad's private memory. */ - /* This is always 0. */ - /* In MB. */ - unsigned int priv_mem_size; /* Size of this quad's */ - /* private memory. */ - /* In MB. */ - unsigned int low_shrd_mem_strp_start;/* Starting address of this */ - /* quad's low shared block */ - /* (untranslated). */ - /* In MB. */ - unsigned int low_shrd_mem_start; /* Starting address of this */ - /* quad's low shared memory */ - /* (untranslated). */ - /* In MB. */ - unsigned int low_shrd_mem_size; /* Size of this quad's low */ - /* shared memory. */ - /* In MB. */ - unsigned int lmmio_copb_start; /* Starting address of this */ - /* quad's local memory */ - /* mapped I/O in the */ - /* compatibility OPB. */ - /* In MB. */ - unsigned int lmmio_copb_size; /* Size of this quad's local */ - /* memory mapped I/O in the */ - /* compatibility OPB. */ - /* In MB. */ - unsigned int lmmio_nopb_start; /* Starting address of this */ - /* quad's local memory */ - /* mapped I/O in the */ - /* non-compatibility OPB. */ - /* In MB. */ - unsigned int lmmio_nopb_size; /* Size of this quad's local */ - /* memory mapped I/O in the */ - /* non-compatibility OPB. */ - /* In MB. */ - unsigned int io_apic_0_start; /* Starting address of I/O */ - /* APIC 0. */ - unsigned int io_apic_0_sz; /* Size I/O APIC 0. */ - unsigned int io_apic_1_start; /* Starting address of I/O */ - /* APIC 1. */ - unsigned int io_apic_1_sz; /* Size I/O APIC 1. */ - unsigned int hi_shrd_mem_start; /* Starting address of this */ - /* quad's high shared memory.*/ - /* In MB. */ - unsigned int hi_shrd_mem_size; /* Size of this quad's high */ - /* shared memory. */ - /* In MB. */ - unsigned int mps_table_addr; /* Address of this quad's */ - /* MPS tables from BIOS, */ - /* in system space.*/ - unsigned int lcl_MDC_pio_addr; /* Port-I/O address for */ - /* local access of MDC. */ - unsigned int rmt_MDC_mmpio_addr; /* MM-Port-I/O address for */ - /* remote access of MDC. */ - unsigned int mm_port_io_start; /* Starting address of this */ - /* quad's memory mapped Port */ - /* I/O space. */ - unsigned int mm_port_io_size; /* Size of this quad's memory*/ - /* mapped Port I/O space. */ - unsigned int mm_rmt_io_apic_start; /* Starting address of this */ - /* quad's memory mapped */ - /* remote I/O APIC space. */ - unsigned int mm_rmt_io_apic_size; /* Size of this quad's memory*/ - /* mapped remote I/O APIC */ - /* space. */ - unsigned int mm_isa_start; /* Starting address of this */ - /* quad's memory mapped ISA */ - /* space (contains MDC */ - /* memory space). */ - unsigned int mm_isa_size; /* Size of this quad's memory*/ - /* mapped ISA space (contains*/ - /* MDC memory space). */ - unsigned int rmt_qmi_addr; /* Remote addr to access QMI.*/ - unsigned int lcl_qmi_addr; /* Local addr to access QMI. */ -}; - -/* - * Note: This structure must be NOT be changed unless the multiproc and - * OS are changed to reflect the new structure. - */ -struct sys_cfg_data { - unsigned int quad_id; - unsigned int bsp_proc_id; /* Boot Strap Processor in this quad. */ - unsigned int scd_version; /* Version number of this table. */ - unsigned int first_quad_id; - unsigned int quads_present31_0; /* 1 bit for each quad */ - unsigned int quads_present63_32; /* 1 bit for each quad */ - unsigned int config_flags; - unsigned int boot_flags; - unsigned int csr_start_addr; /* Absolute value (not in MB) */ - unsigned int csr_size; /* Absolute value (not in MB) */ - unsigned int lcl_apic_start_addr; /* Absolute value (not in MB) */ - unsigned int lcl_apic_size; /* Absolute value (not in MB) */ - unsigned int low_shrd_mem_base; /* 0 or 512MB or 1GB */ - unsigned int low_shrd_mem_quad_offset; /* 0,128M,256M,512M,1G */ - /* may not be totally populated */ - unsigned int split_mem_enbl; /* 0 for no low shared memory */ - unsigned int mmio_sz; /* Size of total system memory mapped I/O */ - /* (in MB). */ - unsigned int quad_spin_lock; /* Spare location used for quad */ - /* bringup. */ - unsigned int nonzero55; /* For checksumming. */ - unsigned int nonzeroaa; /* For checksumming. */ - unsigned int scd_magic_number; - unsigned int system_type; - unsigned int checksum; - /* - * memory configuration area for each quad - */ - struct eachquadmem eq[MAX_NUMNODES]; /* indexed by quad id */ -}; - -void numaq_tsc_disable(void); - -#endif /* CONFIG_X86_NUMAQ */ -#endif /* _ASM_X86_NUMAQ_H */ - diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index d62c9f809bc..9264f04a4c5 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -39,12 +39,6 @@ static inline void vsmp_init(void) { } void setup_bios_corruption_check(void); -#ifdef CONFIG_X86_VISWS -extern void visws_early_detect(void); -#else -static inline void visws_early_detect(void) { } -#endif - extern unsigned long saved_video_mode; extern void reserve_standard_io_resources(void); diff --git a/arch/x86/include/asm/visws/cobalt.h b/arch/x86/include/asm/visws/cobalt.h deleted file mode 100644 index 2edb37637ea..00000000000 --- a/arch/x86/include/asm/visws/cobalt.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _ASM_X86_VISWS_COBALT_H -#define _ASM_X86_VISWS_COBALT_H - -#include <asm/fixmap.h> - -/* - * Cobalt SGI Visual Workstation system ASIC - */ - -#define CO_CPU_NUM_PHYS 0x1e00 -#define CO_CPU_TAB_PHYS (CO_CPU_NUM_PHYS + 2) - -#define CO_CPU_MAX 4 - -#define CO_CPU_PHYS 0xc2000000 -#define CO_APIC_PHYS 0xc4000000 - -/* see set_fixmap() and asm/fixmap.h */ -#define CO_CPU_VADDR (fix_to_virt(FIX_CO_CPU)) -#define CO_APIC_VADDR (fix_to_virt(FIX_CO_APIC)) - -/* Cobalt CPU registers -- relative to CO_CPU_VADDR, use co_cpu_*() */ -#define CO_CPU_REV 0x08 -#define CO_CPU_CTRL 0x10 -#define CO_CPU_STAT 0x20 -#define CO_CPU_TIMEVAL 0x30 - -/* CO_CPU_CTRL bits */ -#define CO_CTRL_TIMERUN 0x04 /* 0 == disabled */ -#define CO_CTRL_TIMEMASK 0x08 /* 0 == unmasked */ - -/* CO_CPU_STATUS bits */ -#define CO_STAT_TIMEINTR 0x02 /* (r) 1 == int pend, (w) 0 == clear */ - -/* CO_CPU_TIMEVAL value */ -#define CO_TIME_HZ 100000000 /* Cobalt core rate */ - -/* Cobalt APIC registers -- relative to CO_APIC_VADDR, use co_apic_*() */ -#define CO_APIC_HI(n) (((n) * 0x10) + 4) -#define CO_APIC_LO(n) ((n) * 0x10) -#define CO_APIC_ID 0x0ffc - -/* CO_APIC_ID bits */ -#define CO_APIC_ENABLE 0x00000100 - -/* CO_APIC_LO bits */ -#define CO_APIC_MASK 0x00010000 /* 0 = enabled */ -#define CO_APIC_LEVEL 0x00008000 /* 0 = edge */ - -/* - * Where things are physically wired to Cobalt - * #defines with no board _<type>_<rev>_ are common to all (thus far) - */ -#define CO_APIC_IDE0 4 -#define CO_APIC_IDE1 2 /* Only on 320 */ - -#define CO_APIC_8259 12 /* serial, floppy, par-l-l */ - -/* Lithium PCI Bridge A -- "the one with 82557 Ethernet" */ -#define CO_APIC_PCIA_BASE0 0 /* and 1 */ /* slot 0, line 0 */ -#define CO_APIC_PCIA_BASE123 5 /* and 6 */ /* slot 0, line 1 */ - -#define CO_APIC_PIIX4_USB 7 /* this one is weird */ - -/* Lithium PCI Bridge B -- "the one with PIIX4" */ -#define CO_APIC_PCIB_BASE0 8 /* and 9-12 *//* slot 0, line 0 */ -#define CO_APIC_PCIB_BASE123 13 /* 14.15 */ /* slot 0, line 1 */ - -#define CO_APIC_VIDOUT0 16 -#define CO_APIC_VIDOUT1 17 -#define CO_APIC_VIDIN0 18 -#define CO_APIC_VIDIN1 19 - -#define CO_APIC_LI_AUDIO 22 - -#define CO_APIC_AS 24 -#define CO_APIC_RE 25 - -#define CO_APIC_CPU 28 /* Timer and Cache interrupt */ -#define CO_APIC_NMI 29 -#define CO_APIC_LAST CO_APIC_NMI - -/* - * This is how irqs are assigned on the Visual Workstation. - * Legacy devices get irq's 1-15 (system clock is 0 and is CO_APIC_CPU). - * All other devices (including PCI) go to Cobalt and are irq's 16 on up. - */ -#define CO_IRQ_APIC0 16 /* irq of apic entry 0 */ -#define IS_CO_APIC(irq) ((irq) >= CO_IRQ_APIC0) -#define CO_IRQ(apic) (CO_IRQ_APIC0 + (apic)) /* apic ent to irq */ -#define CO_APIC(irq) ((irq) - CO_IRQ_APIC0) /* irq to apic ent */ -#define CO_IRQ_IDE0 14 /* knowledge of... */ -#define CO_IRQ_IDE1 15 /* ... ide driver defaults! */ -#define CO_IRQ_8259 CO_IRQ(CO_APIC_8259) - -#ifdef CONFIG_X86_VISWS_APIC -static inline void co_cpu_write(unsigned long reg, unsigned long v) -{ - *((volatile unsigned long *)(CO_CPU_VADDR+reg))=v; -} - -static inline unsigned long co_cpu_read(unsigned long reg) -{ - return *((volatile unsigned long *)(CO_CPU_VADDR+reg)); -} - -static inline void co_apic_write(unsigned long reg, unsigned long v) -{ - *((volatile unsigned long *)(CO_APIC_VADDR+reg))=v; -} - -static inline unsigned long co_apic_read(unsigned long reg) -{ - return *((volatile unsigned long *)(CO_APIC_VADDR+reg)); -} -#endif - -extern char visws_board_type; - -#define VISWS_320 0 -#define VISWS_540 1 - -extern char visws_board_rev; - -extern int pci_visws_init(void); - -#endif /* _ASM_X86_VISWS_COBALT_H */ diff --git a/arch/x86/include/asm/visws/lithium.h b/arch/x86/include/asm/visws/lithium.h deleted file mode 100644 index a10d89bc127..00000000000 --- a/arch/x86/include/asm/visws/lithium.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _ASM_X86_VISWS_LITHIUM_H -#define _ASM_X86_VISWS_LITHIUM_H - -#include <asm/fixmap.h> - -/* - * Lithium is the SGI Visual Workstation I/O ASIC - */ - -#define LI_PCI_A_PHYS 0xfc000000 /* Enet is dev 3 */ -#define LI_PCI_B_PHYS 0xfd000000 /* PIIX4 is here */ - -/* see set_fixmap() and asm/fixmap.h */ -#define LI_PCIA_VADDR (fix_to_virt(FIX_LI_PCIA)) -#define LI_PCIB_VADDR (fix_to_virt(FIX_LI_PCIB)) - -/* Not a standard PCI? (not in linux/pci.h) */ -#define LI_PCI_BUSNUM 0x44 /* lo8: primary, hi8: sub */ -#define LI_PCI_INTEN 0x46 - -/* LI_PCI_INTENT bits */ -#define LI_INTA_0 0x0001 -#define LI_INTA_1 0x0002 -#define LI_INTA_2 0x0004 -#define LI_INTA_3 0x0008 -#define LI_INTA_4 0x0010 -#define LI_INTB 0x0020 -#define LI_INTC 0x0040 -#define LI_INTD 0x0080 - -/* More special purpose macros... */ -static inline void li_pcia_write16(unsigned long reg, unsigned short v) -{ - *((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v; -} - -static inline unsigned short li_pcia_read16(unsigned long reg) -{ - return *((volatile unsigned short *)(LI_PCIA_VADDR+reg)); -} - -static inline void li_pcib_write16(unsigned long reg, unsigned short v) -{ - *((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v; -} - -static inline unsigned short li_pcib_read16(unsigned long reg) -{ - return *((volatile unsigned short *)(LI_PCIB_VADDR+reg)); -} - -#endif /* _ASM_X86_VISWS_LITHIUM_H */ - diff --git a/arch/x86/include/asm/visws/piix4.h b/arch/x86/include/asm/visws/piix4.h deleted file mode 100644 index d0af4d338e7..00000000000 --- a/arch/x86/include/asm/visws/piix4.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _ASM_X86_VISWS_PIIX4_H -#define _ASM_X86_VISWS_PIIX4_H - -/* - * PIIX4 as used on SGI Visual Workstations - */ - -#define PIIX_PM_START 0x0F80 - -#define SIO_GPIO_START 0x0FC0 - -#define SIO_PM_START 0x0FC8 - -#define PMBASE PIIX_PM_START -#define GPIREG0 (PMBASE+0x30) -#define GPIREG(x) (GPIREG0+((x)/8)) -#define GPIBIT(x) (1 << ((x)%8)) - -#define PIIX_GPI_BD_ID1 18 -#define PIIX_GPI_BD_ID2 19 -#define PIIX_GPI_BD_ID3 20 -#define PIIX_GPI_BD_ID4 21 -#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) -#define PIIX_GPI_BD_MASK (GPIBIT(PIIX_GPI_BD_ID1) | \ - GPIBIT(PIIX_GPI_BD_ID2) | \ - GPIBIT(PIIX_GPI_BD_ID3) | \ - GPIBIT(PIIX_GPI_BD_ID4) ) - -#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) - -#define SIO_INDEX 0x2e -#define SIO_DATA 0x2f - -#define SIO_DEV_SEL 0x7 -#define SIO_DEV_ENB 0x30 -#define SIO_DEV_MSB 0x60 -#define SIO_DEV_LSB 0x61 - -#define SIO_GP_DEV 0x7 - -#define SIO_GP_BASE SIO_GPIO_START -#define SIO_GP_MSB (SIO_GP_BASE>>8) -#define SIO_GP_LSB (SIO_GP_BASE&0xff) - -#define SIO_GP_DATA1 (SIO_GP_BASE+0) - -#define SIO_PM_DEV 0x8 - -#define SIO_PM_BASE SIO_PM_START -#define SIO_PM_MSB (SIO_PM_BASE>>8) -#define SIO_PM_LSB (SIO_PM_BASE&0xff) -#define SIO_PM_INDEX (SIO_PM_BASE+0) -#define SIO_PM_DATA (SIO_PM_BASE+1) - -#define SIO_PM_FER2 0x1 - -#define SIO_PM_GP_EN 0x80 - - - -/* - * This is the dev/reg where generating a config cycle will - * result in a PCI special cycle. - */ -#define SPECIAL_DEV 0xff -#define SPECIAL_REG 0x00 - -/* - * PIIX4 needs to see a special cycle with the following data - * to be convinced the processor has gone into the stop grant - * state. PIIX4 insists on seeing this before it will power - * down a system. - */ -#define PIIX_SPECIAL_STOP 0x00120002 - -#define PIIX4_RESET_PORT 0xcf9 -#define PIIX4_RESET_VAL 0x6 - -#define PMSTS_PORT 0xf80 // 2 bytes PM Status -#define PMEN_PORT 0xf82 // 2 bytes PM Enable -#define PMCNTRL_PORT 0xf84 // 2 bytes PM Control - -#define PM_SUSPEND_ENABLE 0x2000 // start sequence to suspend state - -/* - * PMSTS and PMEN I/O bit definitions. - * (Bits are the same in both registers) - */ -#define PM_STS_RSM (1<<15) // Resume Status -#define PM_STS_PWRBTNOR (1<<11) // Power Button Override -#define PM_STS_RTC (1<<10) // RTC status -#define PM_STS_PWRBTN (1<<8) // Power Button Pressed? -#define PM_STS_GBL (1<<5) // Global Status -#define PM_STS_BM (1<<4) // Bus Master Status -#define PM_STS_TMROF (1<<0) // Timer Overflow Status. - -/* - * Stop clock GPI register - */ -#define PIIX_GPIREG0 (0xf80 + 0x30) - -/* - * Stop clock GPI bit in GPIREG0 - */ -#define PIIX_GPI_STPCLK 0x4 // STPCLK signal routed back in - -#endif /* _ASM_X86_VISWS_PIIX4_H */ diff --git a/arch/x86/include/asm/visws/sgivw.h b/arch/x86/include/asm/visws/sgivw.h deleted file mode 100644 index 5fbf63e1003..00000000000 --- a/arch/x86/include/asm/visws/sgivw.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Frame buffer position and size: - */ -extern unsigned long sgivwfb_mem_phys; -extern unsigned long sgivwfb_mem_size; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 8e61d23b8f6..86281ffb96d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -903,10 +903,6 @@ static int __init acpi_parse_madt_lapic_entries(void) #ifdef CONFIG_X86_IO_APIC #define MP_ISA_BUS 0 -#ifdef CONFIG_X86_ES7000 -extern int es7000_plat; -#endif - void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) { int ioapic; @@ -956,14 +952,6 @@ void __init mp_config_acpi_legacy_irqs(void) set_bit(MP_ISA_BUS, mp_bus_not_pci); pr_debug("Bus #%d is ISA\n", MP_ISA_BUS); -#ifdef CONFIG_X86_ES7000 - /* - * Older generations of ES7000 have no legacy identity mappings - */ - if (es7000_plat == 1) - return; -#endif - /* * Use the default configuration for the IRQs 0-15. Unless * overridden by (MADT) interrupt source override entries. diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 0ae0323b1f9..dcb5b15401c 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -18,10 +18,7 @@ obj-y += apic_flat_64.o endif # APIC probe will depend on the listing order here -obj-$(CONFIG_X86_NUMAQ) += numaq_32.o -obj-$(CONFIG_X86_SUMMIT) += summit_32.o obj-$(CONFIG_X86_BIGSMP) += bigsmp_32.o -obj-$(CONFIG_X86_ES7000) += es7000_32.o # For 32bit, probe_32 need to be listed last obj-$(CONFIG_X86_LOCAL_APIC) += probe_$(BITS).o diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 53e20531470..481ae38f6a4 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -2136,7 +2136,6 @@ int generic_processor_info(int apicid, int version) * * - arch/x86/kernel/mpparse.c: MP_processor_info() * - arch/x86/mm/amdtopology.c: amd_numa_init() - * - arch/x86/platform/visws/visws_quirks.c: MP_processor_info() * * This function is executed with the modified * boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c deleted file mode 100644 index 6f8f8b348a3..00000000000 --- a/arch/x86/kernel/apic/es7000_32.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Written by: Garry Forsgren, Unisys Corporation - * Natalie Protasevich, Unisys Corporation - * - * This file contains the code to configure and interface - * with Unisys ES7000 series hardware system manager. - * - * Copyright (c) 2003 Unisys Corporation. - * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar - * - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Unisys Corporation, Township Line & Union Meeting - * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or: - * - * http://www.unisys.com - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/notifier.h> -#include <linux/spinlock.h> -#include <linux/cpumask.h> -#include <linux/threads.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/reboot.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/acpi.h> -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/nmi.h> -#include <linux/smp.h> -#include <linux/io.h> - -#include <asm/apicdef.h> -#include <linux/atomic.h> -#include <asm/fixmap.h> -#include <asm/mpspec.h> -#include <asm/setup.h> -#include <asm/apic.h> -#include <asm/ipi.h> - -/* - * ES7000 chipsets - */ - -#define NON_UNISYS 0 -#define ES7000_CLASSIC 1 -#define ES7000_ZORRO 2 - -#define MIP_REG 1 -#define MIP_PSAI_REG 4 - -#define MIP_BUSY 1 -#define MIP_SPIN 0xf0000 -#define MIP_VALID 0x0100000000000000ULL -#define MIP_SW_APIC 0x1020b - -#define MIP_PORT(val) ((val >> 32) & 0xffff) - -#define MIP_RD_LO(val) (val & 0xffffffff) - -struct mip_reg { - unsigned long long off_0x00; - unsigned long long off_0x08; - unsigned long long off_0x10; - unsigned long long off_0x18; - unsigned long long off_0x20; - unsigned long long off_0x28; - unsigned long long off_0x30; - unsigned long long off_0x38; -}; - -struct mip_reg_info { - unsigned long long mip_info; - unsigned long long delivery_info; - unsigned long long host_reg; - unsigned long long mip_reg; -}; - -struct psai { - unsigned long long entry_type; - unsigned long long addr; - unsigned long long bep_addr; -}; - -#ifdef CONFIG_ACPI - -struct es7000_oem_table { - struct acpi_table_header Header; - u32 OEMTableAddr; - u32 OEMTableSize; -}; - -static unsigned long oem_addrX; -static unsigned long oem_size; - -#endif - -/* - * ES7000 Globals - */ - -static volatile unsigned long *psai; -static struct mip_reg *mip_reg; -static struct mip_reg *host_reg; -static int mip_port; -static unsigned long mip_addr; -static unsigned long host_addr; - -int es7000_plat; - -/* - * GSI override for ES7000 platforms. - */ - - -static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip) -{ - unsigned long vect = 0, psaival = 0; - - if (psai == NULL) - return -1; - - vect = ((unsigned long)__pa(eip)/0x1000) << 16; - psaival = (0x1000000 | vect | cpu); - - while (*psai & 0x1000000) - ; - - *psai = psaival; - - return 0; -} - -static int es7000_apic_is_cluster(void) -{ - /* MPENTIUMIII */ - if (boot_cpu_data.x86 == 6 && - (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11)) - return 1; - - return 0; -} - -static void setup_unisys(void) -{ - /* - * Determine the generation of the ES7000 currently running. - * - * es7000_plat = 1 if the machine is a 5xx ES7000 box - * es7000_plat = 2 if the machine is a x86_64 ES7000 box - * - */ - if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2)) - es7000_plat = ES7000_ZORRO; - else - es7000_plat = ES7000_CLASSIC; -} - -/* - * Parse the OEM Table: - */ -static int parse_unisys_oem(char *oemptr) -{ - int i; - int success = 0; - unsigned char type, size; - unsigned long val; - char *tp = NULL; - struct psai *psaip = NULL; - struct mip_reg_info *mi; - struct mip_reg *host, *mip; - - tp = oemptr; - - tp += 8; - - for (i = 0; i <= 6; i++) { - type = *tp++; - size = *tp++; - tp -= 2; - switch (type) { - case MIP_REG: - mi = (struct mip_reg_info *)tp; - val = MIP_RD_LO(mi->host_reg); - host_addr = val; - host = (struct mip_reg *)val; - host_reg = __va(host); - val = MIP_RD_LO(mi->mip_reg); - mip_port = MIP_PORT(mi->mip_info); - mip_addr = val; - mip = (struct mip_reg *)val; - mip_reg = __va(mip); - pr_debug("host_reg = 0x%lx\n", - (unsigned long)host_reg); - pr_debug("mip_reg = 0x%lx\n", - (unsigned long)mip_reg); - success++; - break; - case MIP_PSAI_REG: - psaip = (struct psai *)tp; - if (tp != NULL) { - if (psaip->addr) - psai = __va(psaip->addr); - else - psai = NULL; - success++; - } - break; - default: - break; - } - tp += size; - } - - if (success < 2) - es7000_plat = NON_UNISYS; - else - setup_unisys(); - - return es7000_plat; -} - -#ifdef CONFIG_ACPI -static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) -{ - struct acpi_table_header *header = NULL; - struct es7000_oem_table *table; - acpi_size tbl_size; - acpi_status ret; - int i = 0; - - for (;;) { - ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size); - if (!ACPI_SUCCESS(ret)) - return -1; - - if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) - break; - - early_acpi_os_unmap_memory(header, tbl_size); - } - - table = (void *)header; - - oem_addrX = table->OEMTableAddr; - oem_size = table->OEMTableSize; - - early_acpi_os_unmap_memory(header, tbl_size); - - *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, oem_size); - - return 0; -} - -static void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr) -{ - if (!oem_addr) - return; - - __acpi_unmap_table((char *)oem_addr, oem_size); -} - -static int es7000_check_dsdt(void) -{ - struct acpi_table_header header; - - if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) && - !strncmp(header.oem_id, "UNISYS", 6)) - return 1; - return 0; -} - -static int es7000_acpi_ret; - -/* Hook from generic ACPI tables.c */ -static int __init es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - unsigned long oem_addr = 0; - int check_dsdt; - int ret = 0; - - /* check dsdt at first to avoid clear fix_map for oem_addr */ - check_dsdt = es7000_check_dsdt(); - - if (!find_unisys_acpi_oem_table(&oem_addr)) { - if (check_dsdt) { - ret = parse_unisys_oem((char *)oem_addr); - } else { - setup_unisys(); - ret = 1; - } - /* - * we need to unmap it - */ - unmap_unisys_acpi_oem_table(oem_addr); - } - - es7000_acpi_ret = ret; - - return ret && !es7000_apic_is_cluster(); -} - -static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id) -{ - int ret = es7000_acpi_ret; - - return ret && es7000_apic_is_cluster(); -} - -#else /* !CONFIG_ACPI: */ -static int es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - return 0; -} - -static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id) -{ - return 0; -} -#endif /* !CONFIG_ACPI */ - -static void es7000_spin(int n) -{ - int i = 0; - - while (i++ < n) - rep_nop(); -} - -static int es7000_mip_write(struct mip_reg *mip_reg) -{ - int status = 0; - int spin; - - spin = MIP_SPIN; - while ((host_reg->off_0x38 & MIP_VALID) != 0) { - if (--spin <= 0) { - WARN(1, "Timeout waiting for Host Valid Flag\n"); - return -1; - } - es7000_spin(MIP_SPIN); - } - - memcpy(host_reg, mip_reg, sizeof(struct mip_reg)); - outb(1, mip_port); - - spin = MIP_SPIN; - - while ((mip_reg->off_0x38 & MIP_VALID) == 0) { - if (--spin <= 0) { - WARN(1, "Timeout waiting for MIP Valid Flag\n"); - return -1; - } - es7000_spin(MIP_SPIN); - } - - status = (mip_reg->off_0x00 & 0xffff0000000000ULL) >> 48; - mip_reg->off_0x38 &= ~MIP_VALID; - - return status; -} - -static void es7000_enable_apic_mode(void) -{ - struct mip_reg es7000_mip_reg; - int mip_status; - - if (!es7000_plat) - return; - - pr_info("Enabling APIC mode.\n"); - memset(&es7000_mip_reg, 0, sizeof(struct mip_reg)); - es7000_mip_reg.off_0x00 = MIP_SW_APIC; - es7000_mip_reg.off_0x38 = MIP_VALID; - - while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0) - WARN(1, "Command failed, status = %x\n", mip_status); -} - -static unsigned int es7000_get_apic_id(unsigned long x) -{ - return (x >> 24) & 0xFF; -} - -static void es7000_send_IPI_mask(const struct cpumask *mask, int vector) -{ - default_send_IPI_mask_sequence_phys(mask, vector); -} - -static void es7000_send_IPI_allbutself(int vector) -{ - default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); -} - -static void es7000_send_IPI_all(int vector) -{ - es7000_send_IPI_mask(cpu_online_mask, vector); -} - -static int es7000_apic_id_registered(void) -{ - return 1; -} - -static const struct cpumask *target_cpus_cluster(void) -{ - return cpu_all_mask; -} - -static const struct cpumask *es7000_target_cpus(void) -{ - return cpumask_of(smp_processor_id()); -} - -static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid) -{ - return 0; -} - -static unsigned long es7000_check_apicid_present(int bit) -{ - return physid_isset(bit, phys_cpu_present_map); -} - -static int es7000_early_logical_apicid(int cpu) -{ - /* on es7000, logical apicid is the same as physical */ - return early_per_cpu(x86_bios_cpu_apicid, cpu); -} - -static unsigned long calculate_ldr(int cpu) -{ - unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu); - - return SET_APIC_LOGICAL_ID(id); -} - -/* - * Set up the logical destination ID. - * - * Intel recommends to set DFR, LdR and TPR before enabling - * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel - * document number 292116). So here it goes... - */ -static void es7000_init_apic_ldr_cluster(void) -{ - unsigned long val; - int cpu = smp_processor_id(); - - apic_write(APIC_DFR, APIC_DFR_CLUSTER); - val = calculate_ldr(cpu); - apic_write(APIC_LDR, val); -} - -static void es7000_init_apic_ldr(void) -{ - unsigned long val; - int cpu = smp_processor_id(); - - apic_write(APIC_DFR, APIC_DFR_FLAT); - val = calculate_ldr(cpu); - apic_write(APIC_LDR, val); -} - -static void es7000_setup_apic_routing(void) -{ - int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id()); - - pr_info("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n", - (apic_version[apic] == 0x14) ? - "Physical Cluster" : "Logical Cluster", - nr_ioapics, cpumask_bits(es7000_target_cpus())[0]); -} - -static int es7000_cpu_present_to_apicid(int mps_cpu) -{ - if (!mps_cpu) - return boot_cpu_physical_apicid; - else if (mps_cpu < nr_cpu_ids) - return per_cpu(x86_bios_cpu_apicid, mps_cpu); - else - return BAD_APICID; -} - -static int cpu_id; - -static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap) -{ - physid_set_mask_of_physid(cpu_id, retmap); - ++cpu_id; -} - -static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap) -{ - /* For clustered we don't have a good way to do this yet - hack */ - physids_promote(0xFFL, retmap); -} - -static int es7000_check_phys_apicid_present(int cpu_physical_apicid) -{ - boot_cpu_physical_apicid = read_apic_id(); - return 1; -} - -static inline int -es7000_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id) -{ - unsigned int round = 0; - unsigned int cpu, uninitialized_var(apicid); - - /* - * The cpus in the mask must all be on the apic cluster. - */ - for_each_cpu_and(cpu, cpumask, cpu_online_mask) { - int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu); - - if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) { - WARN(1, "Not a valid mask!"); - - return -EINVAL; - } - apicid |= new_apicid; - round++; - } - if (!round) - return -EINVAL; - *dest_id = apicid; - return 0; -} - -static int -es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask, - const struct cpumask *andmask, - unsigned int *apicid) -{ - cpumask_var_t cpumask; - *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0); - - if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC)) - return 0; - - cpumask_and(cpumask, inmask, andmask); - es7000_cpu_mask_to_apicid(cpumask, apicid); - - free_cpumask_var(cpumask); - - return 0; -} - -static int es7000_phys_pkg_id(int cpuid_apic, int index_msb) -{ - return cpuid_apic >> index_msb; -} - -static int probe_es7000(void) -{ - /* probed later in mptable/ACPI hooks */ - return 0; -} - -static int es7000_mps_ret; -static int es7000_mps_oem_check(struct mpc_table *mpc, char *oem, - char *productid) -{ - int ret = 0; - - if (mpc->oemptr) { - struct mpc_oemtable *oem_table = - (struct mpc_oemtable *)mpc->oemptr; - - if (!strncmp(oem, "UNISYS", 6)) - ret = parse_unisys_oem((char *)oem_table); - } - - es7000_mps_ret = ret; - - return ret && !es7000_apic_is_cluster(); -} - -static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem, - char *productid) -{ - int ret = es7000_mps_ret; - - return ret && es7000_apic_is_cluster(); -} - -/* We've been warned by a false positive warning.Use __refdata to keep calm. */ -static struct apic __refdata apic_es7000_cluster = { - - .name = "es7000", - .probe = probe_es7000, - .acpi_madt_oem_check = es7000_acpi_madt_oem_check_cluster, - .apic_id_valid = default_apic_id_valid, - .apic_id_registered = es7000_apic_id_registered, - - .irq_delivery_mode = dest_LowestPrio, - /* logical delivery broadcast to all procs: */ - .irq_dest_mode = 1, - - .target_cpus = target_cpus_cluster, - .disable_esr = 1, - .dest_logical = 0, - .check_apicid_used = es7000_check_apicid_used, - .check_apicid_present = es7000_check_apicid_present, - - .vector_allocation_domain = flat_vector_allocation_domain, - .init_apic_ldr = es7000_init_apic_ldr_cluster, - - .ioapic_phys_id_map = es7000_ioapic_phys_id_map, - .setup_apic_routing = es7000_setup_apic_routing, - .multi_timer_check = NULL, - .cpu_present_to_apicid = es7000_cpu_present_to_apicid, - .apicid_to_cpu_present = es7000_apicid_to_cpu_present, - .setup_portio_remap = NULL, - .check_phys_apicid_present = es7000_check_phys_apicid_present, - .enable_apic_mode = es7000_enable_apic_mode, - .phys_pkg_id = es7000_phys_pkg_id, - .mps_oem_check = es7000_mps_oem_check_cluster, - - .get_apic_id = es7000_get_apic_id, - .set_apic_id = NULL, - .apic_id_mask = 0xFF << 24, - - .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and, - - .send_IPI_mask = es7000_send_IPI_mask, - .send_IPI_mask_allbutself = NULL, - .send_IPI_allbutself = es7000_send_IPI_allbutself, - .send_IPI_all = es7000_send_IPI_all, - .send_IPI_self = default_send_IPI_self, - - .wakeup_secondary_cpu = wakeup_secondary_cpu_via_mip, - - .trampoline_phys_low = 0x467, - .trampoline_phys_high = 0x469, - - .wait_for_init_deassert = false, - /* Nothing to do for most platforms, since cleared by the INIT cycle: */ - .smp_callin_clear_local_apic = NULL, - .inquire_remote_apic = default_inquire_remote_apic, - - .read = native_apic_mem_read, - .write = native_apic_mem_write, - .eoi_write = native_apic_mem_write, - .icr_read = native_apic_icr_read, - .icr_write = native_apic_icr_write, - .wait_icr_idle = native_apic_wait_icr_idle, - .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, - - .x86_32_early_logical_apicid = es7000_early_logical_apicid, -}; - -static struct apic __refdata apic_es7000 = { - - .name = "es7000", - .probe = probe_es7000, - .acpi_madt_oem_check = es7000_acpi_madt_oem_check, - .apic_id_valid = default_apic_id_valid, - .apic_id_registered = es7000_apic_id_registered, - - .irq_delivery_mode = dest_Fixed, - /* phys delivery to target CPUs: */ - .irq_dest_mode = 0, - - .target_cpus = es7000_target_cpus, - .disable_esr = 1, - .dest_logical = 0, - .check_apicid_used = es7000_check_apicid_used, - .check_apicid_present = es7000_check_apicid_present, - - .vector_allocation_domain = flat_vector_allocation_domain, - .init_apic_ldr = es7000_init_apic_ldr, - - .ioapic_phys_id_map = es7000_ioapic_phys_id_map, - .setup_apic_routing = es7000_setup_apic_routing, - .multi_timer_check = NULL, - .cpu_present_to_apicid = es7000_cpu_present_to_apicid, - .apicid_to_cpu_present = es7000_apicid_to_cpu_present, - .setup_portio_remap = NULL, - .check_phys_apicid_present = es7000_check_phys_apicid_present, - .enable_apic_mode = es7000_enable_apic_mode, - .phys_pkg_id = es7000_phys_pkg_id, - .mps_oem_check = es7000_mps_oem_check, - - .get_apic_id = es7000_get_apic_id, - .set_apic_id = NULL, - .apic_id_mask = 0xFF << 24, - - .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and, - - .send_IPI_mask = es7000_send_IPI_mask, - .send_IPI_mask_allbutself = NULL, - .send_IPI_allbutself = es7000_send_IPI_allbutself, - .send_IPI_all = es7000_send_IPI_all, - .send_IPI_self = default_send_IPI_self, - - .trampoline_phys_low = 0x467, - .trampoline_phys_high = 0x469, - - .wait_for_init_deassert = true, - /* Nothing to do for most platforms, since cleared by the INIT cycle: */ - .smp_callin_clear_local_apic = NULL, - .inquire_remote_apic = default_inquire_remote_apic, - - .read = native_apic_mem_read, - .write = native_apic_mem_write, - .eoi_write = native_apic_mem_write, - .icr_read = native_apic_icr_read, - .icr_write = native_apic_icr_write, - .wait_icr_idle = native_apic_wait_icr_idle, - .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, - - .x86_32_early_logical_apicid = es7000_early_logical_apicid, -}; - -/* - * Need to check for es7000 followed by es7000_cluster, so this order - * in apic_drivers is important. - */ -apic_drivers(apic_es7000, apic_es7000_cluster); diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c deleted file mode 100644 index 030ea1c04f7..00000000000 --- a/arch/x86/kernel/apic/numaq_32.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Written by: Patricia Gaughen, IBM Corporation - * - * Copyright (C) 2002, IBM Corp. - * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gone@us.ibm.com> - */ -#include <linux/nodemask.h> -#include <linux/topology.h> -#include <linux/bootmem.h> -#include <linux/memblock.h> -#include <linux/threads.h> -#include <linux/cpumask.h> -#include <linux/kernel.h> -#include <linux/mmzone.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/numa.h> -#include <linux/smp.h> -#include <linux/io.h> -#include <linux/mm.h> - -#include <asm/processor.h> -#include <asm/fixmap.h> -#include <asm/mpspec.h> -#include <asm/numaq.h> -#include <asm/setup.h> -#include <asm/apic.h> -#include <asm/e820.h> -#include <asm/ipi.h> - -int found_numaq; - -/* - * Have to match translation table entries to main table entries by counter - * hence the mpc_record variable .... can't see a less disgusting way of - * doing this .... - */ -struct mpc_trans { - unsigned char mpc_type; - unsigned char trans_len; - unsigned char trans_type; - unsigned char trans_quad; - unsigned char trans_global; - unsigned char trans_local; - unsigned short trans_reserved; -}; - -static int mpc_record; - -static struct mpc_trans *translation_table[MAX_MPC_ENTRY]; - -int mp_bus_id_to_node[MAX_MP_BUSSES]; -int mp_bus_id_to_local[MAX_MP_BUSSES]; -int quad_local_to_mp_bus_id[NR_CPUS/4][4]; - - -static inline void numaq_register_node(int node, struct sys_cfg_data *scd) -{ - struct eachquadmem *eq = scd->eq + node; - u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20; - u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20; - int ret; - - node_set(node, numa_nodes_parsed); - ret = numa_add_memblk(node, start, end); - BUG_ON(ret < 0); -} - -/* - * Function: smp_dump_qct() - * - * Description: gets memory layout from the quad config table. This - * function also updates numa_nodes_parsed with the nodes (quads) present. - */ -static void __init smp_dump_qct(void) -{ - struct sys_cfg_data *scd; - int node; - - scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR); - - for_each_node(node) { - if (scd->quads_present31_0 & (1 << node)) - numaq_register_node(node, scd); - } -} - -void numaq_tsc_disable(void) -{ - if (!found_numaq) - return; - - if (num_online_nodes() > 1) { - printk(KERN_DEBUG "NUMAQ: disabling TSC\n"); - setup_clear_cpu_cap(X86_FEATURE_TSC); - } -} - -static void __init numaq_tsc_init(void) -{ - numaq_tsc_disable(); -} - -static inline int generate_logical_apicid(int quad, int phys_apicid) -{ - return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1); -} - -/* x86_quirks member */ -static int mpc_apic_id(struct mpc_cpu *m) -{ - int quad = translation_table[mpc_record]->trans_quad; - int logical_apicid = generate_logical_apicid(quad, m->apicid); - - printk(KERN_DEBUG - "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n", - m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8, - (m->cpufeature & CPU_MODEL_MASK) >> 4, - m->apicver, quad, logical_apicid); - - return logical_apicid; -} - -/* x86_quirks member */ -static void mpc_oem_bus_info(struct mpc_bus *m, char *name) -{ - int quad = translation_table[mpc_record]->trans_quad; - int local = translation_table[mpc_record]->trans_local; - - mp_bus_id_to_node[m->busid] = quad; - mp_bus_id_to_local[m->busid] = local; - - printk(KERN_INFO "Bus #%d is %s (node %d)\n", m->busid, name, quad); -} - -/* x86_quirks member */ -static void mpc_oem_pci_bus(struct mpc_bus *m) -{ - int quad = translation_table[mpc_record]->trans_quad; - int local = translation_table[mpc_record]->trans_local; - - quad_local_to_mp_bus_id[quad][local] = m->busid; -} - -/* - * Called from mpparse code. - * mode = 0: prescan - * mode = 1: one mpc entry scanned - */ -static void numaq_mpc_record(unsigned int mode) -{ - if (!mode) - mpc_record = 0; - else - mpc_record++; -} - -static void __init MP_translation_info(struct mpc_trans *m) -{ - printk(KERN_INFO - "Translation: record %d, type %d, quad %d, global %d, local %d\n", - mpc_record, m->trans_type, m->trans_quad, m->trans_global, - m->trans_local); - - if (mpc_record >= MAX_MPC_ENTRY) - printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); - else - translation_table[mpc_record] = m; /* stash this for later */ - - if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) - node_set_online(m->trans_quad); -} - -static int __init mpf_checksum(unsigned char *mp, int len) -{ - int sum = 0; - - while (len--) - sum += *mp++; - - return sum & 0xFF; -} - -/* - * Read/parse the MPC oem tables - */ -static void __init smp_read_mpc_oem(struct mpc_table *mpc) -{ - struct mpc_oemtable *oemtable = (void *)(long)mpc->oemptr; - int count = sizeof(*oemtable); /* the header size */ - unsigned char *oemptr = ((unsigned char *)oemtable) + count; - - mpc_record = 0; - printk(KERN_INFO - "Found an OEM MPC table at %8p - parsing it...\n", oemtable); - - if (memcmp(oemtable->signature, MPC_OEM_SIGNATURE, 4)) { - printk(KERN_WARNING - "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", - oemtable->signature[0], oemtable->signature[1], - oemtable->signature[2], oemtable->signature[3]); - return; - } - - if (mpf_checksum((unsigned char *)oemtable, oemtable->length)) { - printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); - return; - } - - while (count < oemtable->length) { - switch (*oemptr) { - case MP_TRANSLATION: - { - struct mpc_trans *m = (void *)oemptr; - - MP_translation_info(m); - oemptr += sizeof(*m); - count += sizeof(*m); - ++mpc_record; - break; - } - default: - printk(KERN_WARNING - "Unrecognised OEM table entry type! - %d\n", - (int)*oemptr); - return; - } - } -} - -static __init void early_check_numaq(void) -{ - /* - * get boot-time SMP configuration: - */ - if (smp_found_config) - early_get_smp_config(); - - if (found_numaq) { - x86_init.mpparse.mpc_record = numaq_mpc_record; - x86_init.mpparse.setup_ioapic_ids = x86_init_noop; - x86_init.mpparse.mpc_apic_id = mpc_apic_id; - x86_init.mpparse.smp_read_mpc_oem = smp_read_mpc_oem; - x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus; - x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info; - x86_init.timers.tsc_pre_init = numaq_tsc_init; - x86_init.pci.init = pci_numaq_init; - } -} - -int __init numaq_numa_init(void) -{ - early_check_numaq(); - if (!found_numaq) - return -ENOENT; - smp_dump_qct(); - - return 0; -} - -#define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER) - -static inline unsigned int numaq_get_apic_id(unsigned long x) -{ - return (x >> 24) & 0x0F; -} - -static inline void numaq_send_IPI_mask(const struct cpumask *mask, int vector) -{ - default_send_IPI_mask_sequence_logical(mask, vector); -} - -static inline void numaq_send_IPI_allbutself(int vector) -{ - default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector); -} - -static inline void numaq_send_IPI_all(int vector) -{ - numaq_send_IPI_mask(cpu_online_mask, vector); -} - -#define NUMAQ_TRAMPOLINE_PHYS_LOW (0x8) -#define NUMAQ_TRAMPOLINE_PHYS_HIGH (0xa) - -/* - * Because we use NMIs rather than the INIT-STARTUP sequence to - * bootstrap the CPUs, the APIC may be in a weird state. Kick it: - */ -static inline void numaq_smp_callin_clear_local_apic(void) -{ - clear_local_APIC(); -} - -static inline const struct cpumask *numaq_target_cpus(void) -{ - return cpu_all_mask; -} - -static unsigned long numaq_check_apicid_used(physid_mask_t *map, int apicid) -{ - return physid_isset(apicid, *map); -} - -static inline unsigned long numaq_check_apicid_present(int bit) -{ - return physid_isset(bit, phys_cpu_present_map); -} - -static inline int numaq_apic_id_registered(void) -{ - return 1; -} - -static inline void numaq_init_apic_ldr(void) -{ - /* Already done in NUMA-Q firmware */ -} - -static inline void numaq_setup_apic_routing(void) -{ - printk(KERN_INFO - "Enabling APIC mode: NUMA-Q. Using %d I/O APICs\n", - nr_ioapics); -} - -/* - * Skip adding the timer int on secondary nodes, which causes - * a small but painful rift in the time-space continuum. - */ -static inline int numaq_multi_timer_check(int apic, int irq) -{ - return apic != 0 && irq == 0; -} - -static inline void numaq_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap) -{ - /* We don't have a good way to do this yet - hack */ - return physids_promote(0xFUL, retmap); -} - -/* - * Supporting over 60 cpus on NUMA-Q requires a locality-dependent - * cpu to APIC ID relation to properly interact with the intelligent - * mode of the cluster controller. - */ -static inline int numaq_cpu_present_to_apicid(int mps_cpu) -{ - if (mps_cpu < 60) - return ((mps_cpu >> 2) << 4) | (1 << (mps_cpu & 0x3)); - else - return BAD_APICID; -} - -static inline int numaq_apicid_to_node(int logical_apicid) -{ - return logical_apicid >> 4; -} - -static int numaq_numa_cpu_node(int cpu) -{ - int logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu); - - if (logical_apicid != BAD_APICID) - return numaq_apicid_to_node(logical_apicid); - return NUMA_NO_NODE; -} - -static void numaq_apicid_to_cpu_present(int logical_apicid, physid_mask_t *retmap) -{ - int node = numaq_apicid_to_node(logical_apicid); - int cpu = __ffs(logical_apicid & 0xf); - - physid_set_mask_of_physid(cpu + 4*node, retmap); -} - -/* Where the IO area was mapped on multiquad, always 0 otherwise */ -void *xquad_portio; - -static inline int numaq_check_phys_apicid_present(int phys_apicid) -{ - return 1; -} - -/* - * We use physical apicids here, not logical, so just return the default - * physical broadcast to stop people from breaking us - */ -static int -numaq_cpu_mask_to_apicid_and(const struct cpumask *cpumask, - const struct cpumask *andmask, - unsigned int *apicid) -{ - *apicid = 0x0F; - return 0; -} - -/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */ -static inline int numaq_phys_pkg_id(int cpuid_apic, int index_msb) -{ - return cpuid_apic >> index_msb; -} - -static int -numaq_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid) -{ - if (strncmp(oem, "IBM NUMA", 8)) - printk(KERN_ERR "Warning! Not a NUMA-Q system!\n"); - else - found_numaq = 1; - - return found_numaq; -} - -static int probe_numaq(void) -{ - /* already know from get_memcfg_numaq() */ - return found_numaq; -} - -static void numaq_setup_portio_remap(void) -{ - int num_quads = num_online_nodes(); - - if (num_quads <= 1) - return; - - printk(KERN_INFO - "Remapping cross-quad port I/O for %d quads\n", num_quads); - - xquad_portio = ioremap(XQUAD_PORTIO_BASE, num_quads*XQUAD_PORTIO_QUAD); - - printk(KERN_INFO - "xquad_portio vaddr 0x%08lx, len %08lx\n", - (u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD); -} - -/* Use __refdata to keep false positive warning calm. */ -static struct apic __refdata apic_numaq = { - - .name = "NUMAQ", - .probe = probe_numaq, - .acpi_madt_oem_check = NULL, - .apic_id_valid = default_apic_id_valid, - .apic_id_registered = numaq_apic_id_registered, - - .irq_delivery_mode = dest_LowestPrio, - /* physical delivery on LOCAL quad: */ - .irq_dest_mode = 0, - - .target_cpus = numaq_target_cpus, - .disable_esr = 1, - .dest_logical = APIC_DEST_LOGICAL, - .check_apicid_used = numaq_check_apicid_used, - .check_apicid_present = numaq_check_apicid_present, - - .vector_allocation_domain = flat_vector_allocation_domain, - .init_apic_ldr = numaq_init_apic_ldr, - - .ioapic_phys_id_map = numaq_ioapic_phys_id_map, - .setup_apic_routing = numaq_setup_apic_routing, - .multi_timer_check = numaq_multi_timer_check, - .cpu_present_to_apicid = numaq_cpu_present_to_apicid, - .apicid_to_cpu_present = numaq_apicid_to_cpu_present, - .setup_portio_remap = numaq_setup_portio_remap, - .check_phys_apicid_present = numaq_check_phys_apicid_present, - .enable_apic_mode = NULL, - .phys_pkg_id = numaq_phys_pkg_id, - .mps_oem_check = numaq_mps_oem_check, - - .get_apic_id = numaq_get_apic_id, - .set_apic_id = NULL, - .apic_id_mask = 0x0F << 24, - - .cpu_mask_to_apicid_and = numaq_cpu_mask_to_apicid_and, - - .send_IPI_mask = numaq_send_IPI_mask, - .send_IPI_mask_allbutself = NULL, - .send_IPI_allbutself = numaq_send_IPI_allbutself, - .send_IPI_all = numaq_send_IPI_all, - .send_IPI_self = default_send_IPI_self, - - .wakeup_secondary_cpu = wakeup_secondary_cpu_via_nmi, - .trampoline_phys_low = NUMAQ_TRAMPOLINE_PHYS_LOW, - .trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH, - - /* We don't do anything here because we use NMI's to boot instead */ - .wait_for_init_deassert = false, - .smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic, - .inquire_remote_apic = NULL, - - .read = native_apic_mem_read, - .write = native_apic_mem_write, - .eoi_write = native_apic_mem_write, - .icr_read = native_apic_icr_read, - .icr_write = native_apic_icr_write, - .wait_icr_idle = native_apic_wait_icr_idle, - .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, - - .x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid, - .x86_32_numa_cpu_node = numaq_numa_cpu_node, -}; - -apic_driver(apic_numaq); diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c deleted file mode 100644 index b656128611c..00000000000 --- a/arch/x86/kernel/apic/summit_32.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * IBM Summit-Specific Code - * - * Written By: Matthew Dobson, IBM Corporation - * - * Copyright (c) 2003 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <colpatch@us.ibm.com> - * - */ - -#define pr_fmt(fmt) "summit: %s: " fmt, __func__ - -#include <linux/mm.h> -#include <asm/io.h> -#include <asm/bios_ebda.h> - -/* - * APIC driver for the IBM "Summit" chipset. - */ -#include <linux/threads.h> -#include <linux/cpumask.h> -#include <asm/mpspec.h> -#include <asm/apic.h> -#include <asm/smp.h> -#include <asm/fixmap.h> -#include <asm/apicdef.h> -#include <asm/ipi.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/gfp.h> -#include <linux/smp.h> - -static unsigned summit_get_apic_id(unsigned long x) -{ - return (x >> 24) & 0xFF; -} - -static inline void summit_send_IPI_mask(const struct cpumask *mask, int vector) -{ - default_send_IPI_mask_sequence_logical(mask, vector); -} - -static void summit_send_IPI_allbutself(int vector) -{ - default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector); -} - -static void summit_send_IPI_all(int vector) -{ - summit_send_IPI_mask(cpu_online_mask, vector); -} - -#include <asm/tsc.h> - -extern int use_cyclone; - -#ifdef CONFIG_X86_SUMMIT_NUMA -static void setup_summit(void); -#else -static inline void setup_summit(void) {} -#endif - -static int summit_mps_oem_check(struct mpc_table *mpc, char *oem, - char *productid) -{ - if (!strncmp(oem, "IBM ENSW", 8) && - (!strncmp(productid, "VIGIL SMP", 9) - || !strncmp(productid, "EXA", 3) - || !strncmp(productid, "RUTHLESS SMP", 12))){ - mark_tsc_unstable("Summit based system"); - use_cyclone = 1; /*enable cyclone-timer*/ - setup_summit(); - return 1; - } - return 0; -} - -/* Hook from generic ACPI tables.c */ -static int summit_acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - if (!strncmp(oem_id, "IBM", 3) && - (!strncmp(oem_table_id, "SERVIGIL", 8) - || !strncmp(oem_table_id, "EXA", 3))){ - mark_tsc_unstable("Summit based system"); - use_cyclone = 1; /*enable cyclone-timer*/ - setup_summit(); - return 1; - } - return 0; -} - -struct rio_table_hdr { - unsigned char version; /* Version number of this data structure */ - /* Version 3 adds chassis_num & WP_index */ - unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil) */ - unsigned char num_rio_dev; /* # of RIO I/O devices (Cyclones and Winnipegs) */ -} __attribute__((packed)); - -struct scal_detail { - unsigned char node_id; /* Scalability Node ID */ - unsigned long CBAR; /* Address of 1MB register space */ - unsigned char port0node; /* Node ID port connected to: 0xFF=None */ - unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */ - unsigned char port1node; /* Node ID port connected to: 0xFF = None */ - unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */ - unsigned char port2node; /* Node ID port connected to: 0xFF = None */ - unsigned char port2port; /* Port num port connected to: 0,1,2, or 0xFF=None */ - unsigned char chassis_num; /* 1 based Chassis number (1 = boot node) */ -} __attribute__((packed)); - -struct rio_detail { - unsigned char node_id; /* RIO Node ID */ - unsigned long BBAR; /* Address of 1MB register space */ - unsigned char type; /* Type of device */ - unsigned char owner_id; /* For WPEG: Node ID of Cyclone that owns this WPEG*/ - /* For CYC: Node ID of Twister that owns this CYC */ - unsigned char port0node; /* Node ID port connected to: 0xFF=None */ - unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */ - unsigned char port1node; /* Node ID port connected to: 0xFF=None */ - unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */ - unsigned char first_slot; /* For WPEG: Lowest slot number below this WPEG */ - /* For CYC: 0 */ - unsigned char status; /* For WPEG: Bit 0 = 1 : the XAPIC is used */ - /* = 0 : the XAPIC is not used, ie:*/ - /* ints fwded to another XAPIC */ - /* Bits1:7 Reserved */ - /* For CYC: Bits0:7 Reserved */ - unsigned char WP_index; /* For WPEG: WPEG instance index - lower ones have */ - /* lower slot numbers/PCI bus numbers */ - /* For CYC: No meaning */ - unsigned char chassis_num; /* 1 based Chassis number */ - /* For LookOut WPEGs this field indicates the */ - /* Expansion Chassis #, enumerated from Boot */ - /* Node WPEG external port, then Boot Node CYC */ - /* external port, then Next Vigil chassis WPEG */ - /* external port, etc. */ - /* Shared Lookouts have only 1 chassis number (the */ - /* first one assigned) */ -} __attribute__((packed)); - - -typedef enum { - CompatTwister = 0, /* Compatibility Twister */ - AltTwister = 1, /* Alternate Twister of internal 8-way */ - CompatCyclone = 2, /* Compatibility Cyclone */ - AltCyclone = 3, /* Alternate Cyclone of internal 8-way */ - CompatWPEG = 4, /* Compatibility WPEG */ - AltWPEG = 5, /* Second Planar WPEG */ - LookOutAWPEG = 6, /* LookOut WPEG */ - LookOutBWPEG = 7, /* LookOut WPEG */ -} node_type; - -static inline int is_WPEG(struct rio_detail *rio){ - return (rio->type == CompatWPEG || rio->type == AltWPEG || - rio->type == LookOutAWPEG || rio->type == LookOutBWPEG); -} - -#define SUMMIT_APIC_DFR_VALUE (APIC_DFR_CLUSTER) - -static const struct cpumask *summit_target_cpus(void) -{ - /* CPU_MASK_ALL (0xff) has undefined behaviour with - * dest_LowestPrio mode logical clustered apic interrupt routing - * Just start on cpu 0. IRQ balancing will spread load - */ - return cpumask_of(0); -} - -static unsigned long summit_check_apicid_used(physid_mask_t *map, int apicid) -{ - return 0; -} - -/* we don't use the phys_cpu_present_map to indicate apicid presence */ -static unsigned long summit_check_apicid_present(int bit) -{ - return 1; -} - -static int summit_early_logical_apicid(int cpu) -{ - int count = 0; - u8 my_id = early_per_cpu(x86_cpu_to_apicid, cpu); - u8 my_cluster = APIC_CLUSTER(my_id); -#ifdef CONFIG_SMP - u8 lid; - int i; - - /* Create logical APIC IDs by counting CPUs already in cluster. */ - for (count = 0, i = nr_cpu_ids; --i >= 0; ) { - lid = early_per_cpu(x86_cpu_to_logical_apicid, i); - if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster) - ++count; - } -#endif - /* We only have a 4 wide bitmap in cluster mode. If a deranged - * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */ - BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT); - return my_cluster | (1UL << count); -} - -static void summit_init_apic_ldr(void) -{ - int cpu = smp_processor_id(); - unsigned long id = early_per_cpu(x86_cpu_to_logical_apicid, cpu); - unsigned long val; - - apic_write(APIC_DFR, SUMMIT_APIC_DFR_VALUE); - val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; - val |= SET_APIC_LOGICAL_ID(id); - apic_write(APIC_LDR, val); -} - -static int summit_apic_id_registered(void) -{ - return 1; -} - -static void summit_setup_apic_routing(void) -{ - pr_info("Enabling APIC mode: Summit. Using %d I/O APICs\n", - nr_ioapics); -} - -static int summit_cpu_present_to_apicid(int mps_cpu) -{ - if (mps_cpu < nr_cpu_ids) - return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu); - else - return BAD_APICID; -} - -static void summit_ioapic_phys_id_map(physid_mask_t *phys_id_map, physid_mask_t *retmap) -{ - /* For clustered we don't have a good way to do this yet - hack */ - physids_promote(0x0FL, retmap); -} - -static void summit_apicid_to_cpu_present(int apicid, physid_mask_t *retmap) -{ - physid_set_mask_of_physid(0, retmap); -} - -static int summit_check_phys_apicid_present(int physical_apicid) -{ - return 1; -} - -static inline int -summit_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id) -{ - unsigned int round = 0; - unsigned int cpu, apicid = 0; - - /* - * The cpus in the mask must all be on the apic cluster. - */ - for_each_cpu_and(cpu, cpumask, cpu_online_mask) { - int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu); - - if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) { - pr_err("Not a valid mask!\n"); - return -EINVAL; - } - apicid |= new_apicid; - round++; - } - if (!round) - return -EINVAL; - *dest_id = apicid; - return 0; -} - -static int -summit_cpu_mask_to_apicid_and(const struct cpumask *inmask, - const struct cpumask *andmask, - unsigned int *apicid) -{ - cpumask_var_t cpumask; - *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0); - - if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC)) - return 0; - - cpumask_and(cpumask, inmask, andmask); - summit_cpu_mask_to_apicid(cpumask, apicid); - - free_cpumask_var(cpumask); - - return 0; -} - -/* - * cpuid returns the value latched in the HW at reset, not the APIC ID - * register's value. For any box whose BIOS changes APIC IDs, like - * clustered APIC systems, we must use hard_smp_processor_id. - * - * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID. - */ -static int summit_phys_pkg_id(int cpuid_apic, int index_msb) -{ - return hard_smp_processor_id() >> index_msb; -} - -static int probe_summit(void) -{ - /* probed later in mptable/ACPI hooks */ - return 0; -} - -#ifdef CONFIG_X86_SUMMIT_NUMA -static struct rio_table_hdr *rio_table_hdr; -static struct scal_detail *scal_devs[MAX_NUMNODES]; -static struct rio_detail *rio_devs[MAX_NUMNODES*4]; - -#ifndef CONFIG_X86_NUMAQ -static int mp_bus_id_to_node[MAX_MP_BUSSES]; -#endif - -static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus) -{ - int twister = 0, node = 0; - int i, bus, num_buses; - - for (i = 0; i < rio_table_hdr->num_rio_dev; i++) { - if (rio_devs[i]->node_id == rio_devs[wpeg_num]->owner_id) { - twister = rio_devs[i]->owner_id; - break; - } - } - if (i == rio_table_hdr->num_rio_dev) { - pr_err("Couldn't find owner Cyclone for Winnipeg!\n"); - return last_bus; - } - - for (i = 0; i < rio_table_hdr->num_scal_dev; i++) { - if (scal_devs[i]->node_id == twister) { - node = scal_devs[i]->node_id; - break; - } - } - if (i == rio_table_hdr->num_scal_dev) { - pr_err("Couldn't find owner Twister for Cyclone!\n"); - return last_bus; - } - - switch (rio_devs[wpeg_num]->type) { - case CompatWPEG: - /* - * The Compatibility Winnipeg controls the 2 legacy buses, - * the 66MHz PCI bus [2 slots] and the 2 "extra" buses in case - * a PCI-PCI bridge card is used in either slot: total 5 buses. - */ - num_buses = 5; - break; - case AltWPEG: - /* - * The Alternate Winnipeg controls the 2 133MHz buses [1 slot - * each], their 2 "extra" buses, the 100MHz bus [2 slots] and - * the "extra" buses for each of those slots: total 7 buses. - */ - num_buses = 7; - break; - case LookOutAWPEG: - case LookOutBWPEG: - /* - * A Lookout Winnipeg controls 3 100MHz buses [2 slots each] - * & the "extra" buses for each of those slots: total 9 buses. - */ - num_buses = 9; - break; - default: - pr_info("Unsupported Winnipeg type!\n"); - return last_bus; - } - - for (bus = last_bus; bus < last_bus + num_buses; bus++) - mp_bus_id_to_node[bus] = node; - return bus; -} - -static int build_detail_arrays(void) -{ - unsigned long ptr; - int i, scal_detail_size, rio_detail_size; - - if (rio_table_hdr->num_scal_dev > MAX_NUMNODES) { - pr_warn("MAX_NUMNODES too low! Defined as %d, but system has %d nodes\n", - MAX_NUMNODES, rio_table_hdr->num_scal_dev); - return 0; - } - - switch (rio_table_hdr->version) { - default: - pr_warn("Invalid Rio Grande Table Version: %d\n", - rio_table_hdr->version); - return 0; - case 2: - scal_detail_size = 11; - rio_detail_size = 13; - break; - case 3: - scal_detail_size = 12; - rio_detail_size = 15; - break; - } - - ptr = (unsigned long)rio_table_hdr + 3; - for (i = 0; i < rio_table_hdr->num_scal_dev; i++, ptr += scal_detail_size) - scal_devs[i] = (struct scal_detail *)ptr; - - for (i = 0; i < rio_table_hdr->num_rio_dev; i++, ptr += rio_detail_size) - rio_devs[i] = (struct rio_detail *)ptr; - - return 1; -} - -void setup_summit(void) -{ - unsigned long ptr; - unsigned short offset; - int i, next_wpeg, next_bus = 0; - - /* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */ - ptr = get_bios_ebda(); - ptr = (unsigned long)phys_to_virt(ptr); - - rio_table_hdr = NULL; - offset = 0x180; - while (offset) { - /* The block id is stored in the 2nd word */ - if (*((unsigned short *)(ptr + offset + 2)) == 0x4752) { - /* set the pointer past the offset & block id */ - rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4); - break; - } - /* The next offset is stored in the 1st word. 0 means no more */ - offset = *((unsigned short *)(ptr + offset)); - } - if (!rio_table_hdr) { - pr_err("Unable to locate Rio Grande Table in EBDA - bailing!\n"); - return; - } - - if (!build_detail_arrays()) - return; - - /* The first Winnipeg we're looking for has an index of 0 */ - next_wpeg = 0; - do { - for (i = 0; i < rio_table_hdr->num_rio_dev; i++) { - if (is_WPEG(rio_devs[i]) && rio_devs[i]->WP_index == next_wpeg) { - /* It's the Winnipeg we're looking for! */ - next_bus = setup_pci_node_map_for_wpeg(i, next_bus); - next_wpeg++; - break; - } - } - /* - * If we go through all Rio devices and don't find one with - * the next index, it means we've found all the Winnipegs, - * and thus all the PCI buses. - */ - if (i == rio_table_hdr->num_rio_dev) - next_wpeg = 0; - } while (next_wpeg != 0); -} -#endif - -static struct apic apic_summit = { - - .name = "summit", - .probe = probe_summit, - .acpi_madt_oem_check = summit_acpi_madt_oem_check, - .apic_id_valid = default_apic_id_valid, - .apic_id_registered = summit_apic_id_registered, - - .irq_delivery_mode = dest_LowestPrio, - /* logical delivery broadcast to all CPUs: */ - .irq_dest_mode = 1, - - .target_cpus = summit_target_cpus, - .disable_esr = 1, - .dest_logical = APIC_DEST_LOGICAL, - .check_apicid_used = summit_check_apicid_used, - .check_apicid_present = summit_check_apicid_present, - - .vector_allocation_domain = flat_vector_allocation_domain, - .init_apic_ldr = summit_init_apic_ldr, - - .ioapic_phys_id_map = summit_ioapic_phys_id_map, - .setup_apic_routing = summit_setup_apic_routing, - .multi_timer_check = NULL, - .cpu_present_to_apicid = summit_cpu_present_to_apicid, - .apicid_to_cpu_present = summit_apicid_to_cpu_present, - .setup_portio_remap = NULL, - .check_phys_apicid_present = summit_check_phys_apicid_present, - .enable_apic_mode = NULL, - .phys_pkg_id = summit_phys_pkg_id, - .mps_oem_check = summit_mps_oem_check, - - .get_apic_id = summit_get_apic_id, - .set_apic_id = NULL, - .apic_id_mask = 0xFF << 24, - - .cpu_mask_to_apicid_and = summit_cpu_mask_to_apicid_and, - - .send_IPI_mask = summit_send_IPI_mask, - .send_IPI_mask_allbutself = NULL, - .send_IPI_allbutself = summit_send_IPI_allbutself, - .send_IPI_all = summit_send_IPI_all, - .send_IPI_self = default_send_IPI_self, - - .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW, - .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH, - - .wait_for_init_deassert = true, - .smp_callin_clear_local_apic = NULL, - .inquire_remote_apic = default_inquire_remote_apic, - - .read = native_apic_mem_read, - .write = native_apic_mem_write, - .eoi_write = native_apic_mem_write, - .icr_read = native_apic_icr_read, - .icr_write = native_apic_icr_write, - .wait_icr_idle = native_apic_wait_icr_idle, - .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, - - .x86_32_early_logical_apicid = summit_early_logical_apicid, -}; - -apic_driver(apic_summit); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 897d6201ef1..a80029035bf 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -274,10 +274,6 @@ static void intel_workarounds(struct cpuinfo_x86 *c) } #endif -#ifdef CONFIG_X86_NUMAQ - numaq_tsc_disable(); -#endif - intel_smp_check(c); } #else diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index fa511acff7e..09c76d26555 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -869,7 +869,6 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); - visws_early_detect(); /* * copy kernel address range established so far and switch diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 27aa0455fab..1d045f9c390 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -687,10 +687,6 @@ static int __init dummy_numa_init(void) void __init x86_numa_init(void) { if (!numa_off) { -#ifdef CONFIG_X86_NUMAQ - if (!numa_init(numaq_numa_init)) - return; -#endif #ifdef CONFIG_ACPI_NUMA if (!numa_init(x86_acpi_numa_init)) return; diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index e063eed0f91..5c6fc3577a4 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -13,9 +13,6 @@ obj-y += legacy.o irq.o obj-$(CONFIG_STA2X11) += sta2x11-fixup.o -obj-$(CONFIG_X86_VISWS) += visws.o - -obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o obj-$(CONFIG_X86_INTEL_MID) += intel_mid_pci.o diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index d491deddeba..059a76c2973 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -567,7 +567,6 @@ char * __init pcibios_setup(char *str) pci_probe |= PCI_PROBE_NOEARLY; return NULL; } -#ifndef CONFIG_X86_VISWS else if (!strcmp(str, "usepirqmask")) { pci_probe |= PCI_USE_PIRQ_MASK; return NULL; @@ -577,9 +576,7 @@ char * __init pcibios_setup(char *str) } else if (!strncmp(str, "lastbus=", 8)) { pcibios_last_bus = simple_strtol(str+8, NULL, 0); return NULL; - } -#endif - else if (!strcmp(str, "rom")) { + } else if (!strcmp(str, "rom")) { pci_probe |= PCI_ASSIGN_ROMS; return NULL; } else if (!strcmp(str, "norom")) { diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c deleted file mode 100644 index 080eb0374ff..00000000000 --- a/arch/x86/pci/numaq_32.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * numaq_32.c - Low-level PCI access for NUMA-Q machines - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/nodemask.h> -#include <asm/apic.h> -#include <asm/mpspec.h> -#include <asm/pci_x86.h> -#include <asm/numaq.h> - -#define BUS2QUAD(global) (mp_bus_id_to_node[global]) - -#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) - -#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) - -#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) - -static void write_cf8(unsigned bus, unsigned devfn, unsigned reg) -{ - unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg); - if (xquad_portio) - writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus))); - else - outl(val, 0xCF8); -} - -static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); - - WARN_ON(seg); - if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - raw_spin_lock_irqsave(&pci_config_lock, flags); - - write_cf8(bus, devfn, reg); - - switch (len) { - case 1: - if (xquad_portio) - *value = readb(adr + (reg & 3)); - else - *value = inb(0xCFC + (reg & 3)); - break; - case 2: - if (xquad_portio) - *value = readw(adr + (reg & 2)); - else - *value = inw(0xCFC + (reg & 2)); - break; - case 4: - if (xquad_portio) - *value = readl(adr); - else - *value = inl(0xCFC); - break; - } - - raw_spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); - - WARN_ON(seg); - if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - raw_spin_lock_irqsave(&pci_config_lock, flags); - - write_cf8(bus, devfn, reg); - - switch (len) { - case 1: - if (xquad_portio) - writeb(value, adr + (reg & 3)); - else - outb((u8)value, 0xCFC + (reg & 3)); - break; - case 2: - if (xquad_portio) - writew(value, adr + (reg & 2)); - else - outw((u16)value, 0xCFC + (reg & 2)); - break; - case 4: - if (xquad_portio) - writel(value, adr + reg); - else - outl((u32)value, 0xCFC); - break; - } - - raw_spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -#undef PCI_CONF1_MQ_ADDRESS - -static const struct pci_raw_ops pci_direct_conf1_mq = { - .read = pci_conf1_mq_read, - .write = pci_conf1_mq_write -}; - - -static void pci_fixup_i450nx(struct pci_dev *d) -{ - /* - * i450NX -- Find and scan all secondary buses on all PXB's. - */ - int pxb, reg; - u8 busno, suba, subb; - int quad = BUS2QUAD(d->bus->number); - - dev_info(&d->dev, "searching for i450NX host bridges\n"); - reg = 0xd0; - for(pxb=0; pxb<2; pxb++) { - pci_read_config_byte(d, reg++, &busno); - pci_read_config_byte(d, reg++, &suba); - pci_read_config_byte(d, reg++, &subb); - dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", - pxb, busno, suba, subb); - if (busno) { - /* Bus A */ - pcibios_scan_root(QUADLOCAL2BUS(quad, busno)); - } - if (suba < subb) { - /* Bus B */ - pcibios_scan_root(QUADLOCAL2BUS(quad, suba+1)); - } - } - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); - -int __init pci_numaq_init(void) -{ - int quad; - - raw_pci_ops = &pci_direct_conf1_mq; - - pcibios_scan_root(0); - if (num_online_nodes() > 1) - for_each_online_node(quad) { - if (quad == 0) - continue; - printk("Scanning PCI bus %d for quad %d\n", - QUADLOCAL2BUS(quad,0), quad); - pcibios_scan_root(QUADLOCAL2BUS(quad, 0)); - } - return 0; -} diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c deleted file mode 100644 index cd9d4d1681d..00000000000 --- a/arch/x86/pci/visws.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Low-Level PCI Support for SGI Visual Workstation - * - * (c) 1999--2000 Martin Mares <mj@ucw.cz> - */ - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/init.h> - -#include <asm/setup.h> -#include <asm/pci_x86.h> -#include <asm/visws/cobalt.h> -#include <asm/visws/lithium.h> - -static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; } -static void pci_visws_disable_irq(struct pci_dev *dev) { } - -/* int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; */ -/* void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; */ - -/* void __init pcibios_penalize_isa_irq(int irq, int active) {} */ - - -unsigned int pci_bus0, pci_bus1; - -static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq, bus = dev->bus->number; - - pin--; - - /* Nothing useful at PIIX4 pin 1 */ - if (bus == pci_bus0 && slot == 4 && pin == 0) - return -1; - - /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */ - if (bus == pci_bus0 && slot == 4 && pin == 3) { - irq = CO_IRQ(CO_APIC_PIIX4_USB); - goto out; - } - - /* First pin spread down 1 APIC entry per slot */ - if (pin == 0) { - irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 : - CO_APIC_PCIA_BASE0) + slot); - goto out; - } - - /* lines 1,2,3 from any slot is shared in this twirly pattern */ - if (bus == pci_bus1) { - /* lines 1-3 from devices 0 1 rotate over 2 apic entries */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2)); - } else { /* bus == pci_bus0 */ - /* lines 1-3 from devices 0-3 rotate over 3 apic entries */ - if (slot == 0) - slot = 3; /* same pattern */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3)); - } -out: - printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq); - return irq; -} - -int __init pci_visws_init(void) -{ - pcibios_enable_irq = &pci_visws_enable_irq; - pcibios_disable_irq = &pci_visws_disable_irq; - - /* The VISWS supports configuration access type 1 only */ - pci_probe = (pci_probe | PCI_PROBE_CONF1) & - ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2); - - pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; - pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff; - - printk(KERN_INFO "PCI: Lithium bridge A bus: %u, " - "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); - - raw_pci_ops = &pci_direct_conf1; - pcibios_scan_root(pci_bus0); - pcibios_scan_root(pci_bus1); - pci_fixup_irqs(pci_common_swizzle, visws_map_irq); - pcibios_resource_survey(); - /* Request bus scan */ - return 1; -} diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile index 20342d4c82c..85afde1fa3e 100644 --- a/arch/x86/platform/Makefile +++ b/arch/x86/platform/Makefile @@ -9,5 +9,4 @@ obj-y += olpc/ obj-y += scx200/ obj-y += sfi/ obj-y += ts5500/ -obj-y += visws/ obj-y += uv/ diff --git a/arch/x86/platform/visws/Makefile b/arch/x86/platform/visws/Makefile deleted file mode 100644 index 91bc17ab2fd..00000000000 --- a/arch/x86/platform/visws/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_X86_VISWS) += visws_quirks.o diff --git a/arch/x86/platform/visws/visws_quirks.c b/arch/x86/platform/visws/visws_quirks.c deleted file mode 100644 index 94d8a39332e..00000000000 --- a/arch/x86/platform/visws/visws_quirks.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * SGI Visual Workstation support and quirks, unmaintained. - * - * Split out from setup.c by davej@suse.de - * - * Copyright (C) 1999 Bent Hagemark, Ingo Molnar - * - * SGI Visual Workstation interrupt controller - * - * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC - * which serves as the main interrupt controller in the system. Non-legacy - * hardware in the system uses this controller directly. Legacy devices - * are connected to the PIIX4 which in turn has its 8259(s) connected to - * a of the Cobalt APIC entry. - * - * 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com - * - * 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru> - */ -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/smp.h> - -#include <asm/visws/cobalt.h> -#include <asm/visws/piix4.h> -#include <asm/io_apic.h> -#include <asm/fixmap.h> -#include <asm/reboot.h> -#include <asm/setup.h> -#include <asm/apic.h> -#include <asm/e820.h> -#include <asm/time.h> -#include <asm/io.h> - -#include <linux/kernel_stat.h> - -#include <asm/i8259.h> -#include <asm/irq_vectors.h> -#include <asm/visws/lithium.h> - -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/pci_ids.h> - -extern int no_broadcast; - -char visws_board_type = -1; -char visws_board_rev = -1; - -static void __init visws_time_init(void) -{ - printk(KERN_INFO "Starting Cobalt Timer system clock\n"); - - /* Set the countdown value */ - co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); - - /* Start the timer */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); - - /* Enable (unmask) the timer interrupt */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); - - setup_default_timer_irq(); -} - -/* Replaces the default init_ISA_irqs in the generic setup */ -static void __init visws_pre_intr_init(void); - -/* Quirk for machine specific memory setup. */ - -#define MB (1024 * 1024) - -unsigned long sgivwfb_mem_phys; -unsigned long sgivwfb_mem_size; -EXPORT_SYMBOL(sgivwfb_mem_phys); -EXPORT_SYMBOL(sgivwfb_mem_size); - -long long mem_size __initdata = 0; - -static char * __init visws_memory_setup(void) -{ - long long gfx_mem_size = 8 * MB; - - mem_size = boot_params.alt_mem_k; - - if (!mem_size) { - printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n"); - mem_size = 128 * MB; - } - - /* - * this hardcodes the graphics memory to 8 MB - * it really should be sized dynamically (or at least - * set as a boot param) - */ - if (!sgivwfb_mem_size) { - printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n"); - sgivwfb_mem_size = 8 * MB; - } - - /* - * Trim to nearest MB - */ - sgivwfb_mem_size &= ~((1 << 20) - 1); - sgivwfb_mem_phys = mem_size - gfx_mem_size; - - e820_add_region(0, LOWMEMSIZE(), E820_RAM); - e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM); - e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED); - - return "PROM"; -} - -static void visws_machine_emergency_restart(void) -{ - /* - * Visual Workstations restart after this - * register is poked on the PIIX4 - */ - outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT); -} - -static void visws_machine_power_off(void) -{ - unsigned short pm_status; -/* extern unsigned int pci_bus0; */ - - while ((pm_status = inw(PMSTS_PORT)) & 0x100) - outw(pm_status, PMSTS_PORT); - - outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT); - - mdelay(10); - -#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) - -/* outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */ - outl(PIIX_SPECIAL_STOP, 0xCFC); -} - -static void __init visws_get_smp_config(unsigned int early) -{ -} - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesn't have a BIOS(-configuration table). - * No problem for Linux. - */ - -static void __init MP_processor_info(struct mpc_cpu *m) -{ - int ver, logical_apicid; - physid_mask_t apic_cpus; - - if (!(m->cpuflag & CPU_ENABLED)) - return; - - logical_apicid = m->apicid; - printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n", - m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "", - m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8, - (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver); - - if (m->cpuflag & CPU_BOOTPROCESSOR) - boot_cpu_physical_apicid = m->apicid; - - ver = m->apicver; - if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) { - printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", - m->apicid, MAX_LOCAL_APIC); - return; - } - - apic->apicid_to_cpu_present(m->apicid, &apic_cpus); - physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus); - /* - * Validate version - */ - if (ver == 0x0) { - printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! " - "fixing up to 0x10. (tell your hw vendor)\n", - m->apicid); - ver = 0x10; - } - apic_version[m->apicid] = ver; -} - -static void __init visws_find_smp_config(void) -{ - struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS); - unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS)); - - if (ncpus > CO_CPU_MAX) { - printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n", - ncpus, mp); - - ncpus = CO_CPU_MAX; - } - - if (ncpus > setup_max_cpus) - ncpus = setup_max_cpus; - -#ifdef CONFIG_X86_LOCAL_APIC - smp_found_config = 1; -#endif - while (ncpus--) - MP_processor_info(mp++); - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -static void visws_trap_init(void); - -void __init visws_early_detect(void) -{ - int raw; - - visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) - >> PIIX_GPI_BD_SHIFT; - - if (visws_board_type < 0) - return; - - /* - * Override the default platform setup functions - */ - x86_init.resources.memory_setup = visws_memory_setup; - x86_init.mpparse.get_smp_config = visws_get_smp_config; - x86_init.mpparse.find_smp_config = visws_find_smp_config; - x86_init.irqs.pre_vector_init = visws_pre_intr_init; - x86_init.irqs.trap_init = visws_trap_init; - x86_init.timers.timer_init = visws_time_init; - x86_init.pci.init = pci_visws_init; - x86_init.pci.init_irq = x86_init_noop; - - /* - * Install reboot quirks: - */ - pm_power_off = visws_machine_power_off; - machine_ops.emergency_restart = visws_machine_emergency_restart; - - /* - * Do not use broadcast IPIs: - */ - no_broadcast = 0; - -#ifdef CONFIG_X86_IO_APIC - /* - * Turn off IO-APIC detection and initialization: - */ - skip_ioapic_setup = 1; -#endif - - /* - * Get Board rev. - * First, we have to initialize the 307 part to allow us access - * to the GPIO registers. Let's map them at 0x0fc0 which is right - * after the PIIX4 PM section. - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable GPIO registers. */ - - /* - * Now, we have to map the power management section to write - * a bit which enables access to the GPIO registers. - * What lunatic came up with this shit? - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable PM registers. */ - - /* - * Now, write the PM register which enables the GPIO registers. - */ - outb_p(SIO_PM_FER2, SIO_PM_INDEX); - outb_p(SIO_PM_GP_EN, SIO_PM_DATA); - - /* - * Now, initialize the GPIO registers. - * We want them all to be inputs which is the - * power on default, so let's leave them alone. - * So, let's just read the board rev! - */ - raw = inb_p(SIO_GP_DATA1); - raw &= 0x7f; /* 7 bits of valid board revision ID. */ - - if (visws_board_type == VISWS_320) { - if (raw < 0x6) { - visws_board_rev = 4; - } else if (raw < 0xc) { - visws_board_rev = 5; - } else { - visws_board_rev = 6; - } - } else if (visws_board_type == VISWS_540) { - visws_board_rev = 2; - } else { - visws_board_rev = raw; - } - - printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n", - (visws_board_type == VISWS_320 ? "320" : - (visws_board_type == VISWS_540 ? "540" : - "unknown")), visws_board_rev); -} - -#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4) -#define BCD (LI_INTB | LI_INTC | LI_INTD) -#define ALLDEVS (A01234 | BCD) - -static __init void lithium_init(void) -{ - set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); - set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); - - if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) || - (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) { - printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A'); -/* panic("This machine is not SGI Visual Workstation 320/540"); */ - } - - if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) || - (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) { - printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B'); -/* panic("This machine is not SGI Visual Workstation 320/540"); */ - } - - li_pcia_write16(LI_PCI_INTEN, ALLDEVS); - li_pcib_write16(LI_PCI_INTEN, ALLDEVS); -} - -static __init void cobalt_init(void) -{ - /* - * On normal SMP PC this is used only with SMP, but we have to - * use it and set it up here to start the Cobalt clock - */ - set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); - setup_local_APIC(); - printk(KERN_INFO "Local APIC Version %#x, ID %#x\n", - (unsigned int)apic_read(APIC_LVR), - (unsigned int)apic_read(APIC_ID)); - - set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); - set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); - printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n", - co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID)); - - /* Enable Cobalt APIC being careful to NOT change the ID! */ - co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE); - - printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n", - co_apic_read(CO_APIC_ID)); -} - -static void __init visws_trap_init(void) -{ - lithium_init(); - cobalt_init(); -} - -/* - * IRQ controller / APIC support: - */ - -static DEFINE_SPINLOCK(cobalt_lock); - -/* - * Set the given Cobalt APIC Redirection Table entry to point - * to the given IDT vector/index. - */ -static inline void co_apic_set(int entry, int irq) -{ - co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR)); - co_apic_write(CO_APIC_HI(entry), 0); -} - -/* - * Cobalt (IO)-APIC functions to handle PCI devices. - */ -static inline int co_apic_ide0_hack(void) -{ - extern char visws_board_type; - extern char visws_board_rev; - - if (visws_board_type == VISWS_320 && visws_board_rev == 5) - return 5; - return CO_APIC_IDE0; -} - -static int is_co_apic(unsigned int irq) -{ - if (IS_CO_APIC(irq)) - return CO_APIC(irq); - - switch (irq) { - case 0: return CO_APIC_CPU; - case CO_IRQ_IDE0: return co_apic_ide0_hack(); - case CO_IRQ_IDE1: return CO_APIC_IDE1; - default: return -1; - } -} - - -/* - * This is the SGI Cobalt (IO-)APIC: - */ -static void enable_cobalt_irq(struct irq_data *data) -{ - co_apic_set(is_co_apic(data->irq), data->irq); -} - -static void disable_cobalt_irq(struct irq_data *data) -{ - int entry = is_co_apic(data->irq); - - co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK); - co_apic_read(CO_APIC_LO(entry)); -} - -static void ack_cobalt_irq(struct irq_data *data) -{ - unsigned long flags; - - spin_lock_irqsave(&cobalt_lock, flags); - disable_cobalt_irq(data); - apic_write(APIC_EOI, APIC_EOI_ACK); - spin_unlock_irqrestore(&cobalt_lock, flags); -} - -static struct irq_chip cobalt_irq_type = { - .name = "Cobalt-APIC", - .irq_enable = enable_cobalt_irq, - .irq_disable = disable_cobalt_irq, - .irq_ack = ack_cobalt_irq, -}; - - -/* - * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt - * -- not the manner expected by the code in i8259.c. - * - * there is a 'master' physical interrupt source that gets sent to - * the CPU. But in the chipset there are various 'virtual' interrupts - * waiting to be handled. We represent this to Linux through a 'master' - * interrupt controller type, and through a special virtual interrupt- - * controller. Device drivers only see the virtual interrupt sources. - */ -static unsigned int startup_piix4_master_irq(struct irq_data *data) -{ - legacy_pic->init(0); - enable_cobalt_irq(data); - return 0; -} - -static struct irq_chip piix4_master_irq_type = { - .name = "PIIX4-master", - .irq_startup = startup_piix4_master_irq, - .irq_ack = ack_cobalt_irq, -}; - -static void pii4_mask(struct irq_data *data) { } - -static struct irq_chip piix4_virtual_irq_type = { - .name = "PIIX4-virtual", - .irq_mask = pii4_mask, -}; - -/* - * PIIX4-8259 master/virtual functions to handle interrupt requests - * from legacy devices: floppy, parallel, serial, rtc. - * - * None of these get Cobalt APIC entries, neither do they have IDT - * entries. These interrupts are purely virtual and distributed from - * the 'master' interrupt source: CO_IRQ_8259. - * - * When the 8259 interrupts its handler figures out which of these - * devices is interrupting and dispatches to its handler. - * - * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ - * enable_irq gets the right irq. This 'master' irq is never directly - * manipulated by any driver. - */ -static irqreturn_t piix4_master_intr(int irq, void *dev_id) -{ - unsigned long flags; - int realirq; - - raw_spin_lock_irqsave(&i8259A_lock, flags); - - /* Find out what's interrupting in the PIIX4 master 8259 */ - outb(0x0c, 0x20); /* OCW3 Poll command */ - realirq = inb(0x20); - - /* - * Bit 7 == 0 means invalid/spurious - */ - if (unlikely(!(realirq & 0x80))) - goto out_unlock; - - realirq &= 7; - - if (unlikely(realirq == 2)) { - outb(0x0c, 0xa0); - realirq = inb(0xa0); - - if (unlikely(!(realirq & 0x80))) - goto out_unlock; - - realirq = (realirq & 7) + 8; - } - - /* mask and ack interrupt */ - cached_irq_mask |= 1 << realirq; - if (unlikely(realirq > 7)) { - inb(0xa1); - outb(cached_slave_mask, 0xa1); - outb(0x60 + (realirq & 7), 0xa0); - outb(0x60 + 2, 0x20); - } else { - inb(0x21); - outb(cached_master_mask, 0x21); - outb(0x60 + realirq, 0x20); - } - - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - - /* - * handle this 'virtual interrupt' as a Cobalt one now. - */ - generic_handle_irq(realirq); - - return IRQ_HANDLED; - -out_unlock: - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - return IRQ_NONE; -} - -static struct irqaction master_action = { - .handler = piix4_master_intr, - .name = "PIIX4-8259", - .flags = IRQF_NO_THREAD, -}; - -static struct irqaction cascade_action = { - .handler = no_action, - .name = "cascade", - .flags = IRQF_NO_THREAD, -}; - -static inline void set_piix4_virtual_irq_type(void) -{ - piix4_virtual_irq_type.irq_enable = i8259A_chip.irq_unmask; - piix4_virtual_irq_type.irq_disable = i8259A_chip.irq_mask; - piix4_virtual_irq_type.irq_unmask = i8259A_chip.irq_unmask; -} - -static void __init visws_pre_intr_init(void) -{ - int i; - - set_piix4_virtual_irq_type(); - - for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) { - struct irq_chip *chip = NULL; - - if (i == 0) - chip = &cobalt_irq_type; - else if (i == CO_IRQ_IDE0) - chip = &cobalt_irq_type; - else if (i == CO_IRQ_IDE1) - chip = &cobalt_irq_type; - else if (i == CO_IRQ_8259) - chip = &piix4_master_irq_type; - else if (i < CO_IRQ_APIC0) - chip = &piix4_virtual_irq_type; - else if (IS_CO_APIC(i)) - chip = &cobalt_irq_type; - - if (chip) - irq_set_chip(i, chip); - } - - setup_irq(CO_IRQ_8259, &master_action); - setup_irq(2, &cascade_action); -} diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index 01b90261fa3..9c50cc2e403 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -7,7 +7,7 @@ config XEN depends on PARAVIRT select PARAVIRT_CLOCK select XEN_HAVE_PVMMU - depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS) + depends on X86_64 || (X86_32 && X86_PAE) depends on X86_TSC help This is the Linux Xen port. Enabling this will allow the diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index aed3488d942..f3fe4cb4974 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o -obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c deleted file mode 100644 index 9e0998f2288..00000000000 --- a/drivers/clocksource/cyclone.c +++ /dev/null @@ -1,113 +0,0 @@ -#include <linux/clocksource.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/timex.h> -#include <linux/init.h> - -#include <asm/pgtable.h> -#include <asm/io.h> - -#include <asm/mach_timer.h> - -#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */ -#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */ -#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */ -#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */ -#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */ -#define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */ - -int use_cyclone = 0; -static void __iomem *cyclone_ptr; - -static cycle_t read_cyclone(struct clocksource *cs) -{ - return (cycle_t)readl(cyclone_ptr); -} - -static struct clocksource clocksource_cyclone = { - .name = "cyclone", - .rating = 250, - .read = read_cyclone, - .mask = CYCLONE_TIMER_MASK, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init init_cyclone_clocksource(void) -{ - unsigned long base; /* saved value from CBAR */ - unsigned long offset; - u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */ - u32 __iomem* reg; - int i; - - /* make sure we're on a summit box: */ - if (!use_cyclone) - return -ENODEV; - - printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); - - /* find base address: */ - offset = CYCLONE_CBAR_ADDR; - reg = ioremap_nocache(offset, sizeof(reg)); - if (!reg) { - printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); - return -ENODEV; - } - /* even on 64bit systems, this is only 32bits: */ - base = readl(reg); - iounmap(reg); - if (!base) { - printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); - return -ENODEV; - } - - /* setup PMCC: */ - offset = base + CYCLONE_PMCC_OFFSET; - reg = ioremap_nocache(offset, sizeof(reg)); - if (!reg) { - printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); - return -ENODEV; - } - writel(0x00000001,reg); - iounmap(reg); - - /* setup MPCS: */ - offset = base + CYCLONE_MPCS_OFFSET; - reg = ioremap_nocache(offset, sizeof(reg)); - if (!reg) { - printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); - return -ENODEV; - } - writel(0x00000001,reg); - iounmap(reg); - - /* map in cyclone_timer: */ - offset = base + CYCLONE_MPMC_OFFSET; - cyclone_timer = ioremap_nocache(offset, sizeof(u64)); - if (!cyclone_timer) { - printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); - return -ENODEV; - } - - /* quick test to make sure its ticking: */ - for (i = 0; i < 3; i++){ - u32 old = readl(cyclone_timer); - int stall = 100; - - while (stall--) - barrier(); - - if (readl(cyclone_timer) == old) { - printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); - iounmap(cyclone_timer); - cyclone_timer = NULL; - return -ENODEV; - } - } - cyclone_ptr = cyclone_timer; - - return clocksource_register_hz(&clocksource_cyclone, - CYCLONE_TIMER_FREQ); -} - -arch_initcall(init_cyclone_clocksource); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index e2501ac6fe8..e04fe2d9df3 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_ARM) += setup-irq.o obj-$(CONFIG_UNICORE32) += setup-irq.o obj-$(CONFIG_SUPERH) += setup-irq.o obj-$(CONFIG_MIPS) += setup-irq.o -obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_TILE) += setup-irq.o obj-$(CONFIG_SPARC_LEON) += setup-irq.o obj-$(CONFIG_M68K) += setup-irq.o diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 97dabd39b09..158020522df 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -379,14 +379,7 @@ #define DEBUG_PRINT_NVRAM 0 #define DEBUG_QLA1280 0 -/* - * The SGI VISWS is broken and doesn't support MMIO ;-( - */ -#ifdef CONFIG_X86_VISWS -#define MEMORY_MAPPED_IO 0 -#else #define MEMORY_MAPPED_IO 1 -#endif #include "qla1280.h" diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 97a8f3a12a7..b4b209ce802 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -796,18 +796,9 @@ config FB_HGA As this card technology is at least 25 years old, most people will answer N here. -config FB_SGIVW - tristate "SGI Visual Workstation framebuffer support" - depends on FB && X86_VISWS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - SGI Visual Workstation support for framebuffer graphics. - config FB_GBE bool "SGI Graphics Backend frame buffer support" - depends on (FB = y) && (SGI_IP32 || X86_VISWS) + depends on (FB = y) && SGI_IP32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 08d6a4ab3ac..1be26fe1059 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -75,7 +75,6 @@ obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o -obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 4c7cb368a9d..3ec65a878ac 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -45,10 +45,6 @@ struct gbefb_par { #define GBE_BASE 0x16000000 /* SGI O2 */ #endif -#ifdef CONFIG_X86_VISWS -#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */ -#endif - /* macro for fastest write-though access to the framebuffer */ #ifdef CONFIG_MIPS #ifdef CONFIG_CPU_R10000 diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 39ac49e0682..0037104d66a 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -54,7 +54,7 @@ config LOGO_PARISC_CLUT224 config LOGO_SGI_CLUT224 bool "224-color SGI Linux logo" - depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS + depends on SGI_IP22 || SGI_IP27 || SGI_IP32 default y config LOGO_SUN_CLUT224 diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index b670cbda38e..940cd196eef 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -81,7 +81,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) logo = &logo_parisc_clut224; #endif #ifdef CONFIG_LOGO_SGI_CLUT224 - /* SGI Linux logo on MIPS/MIPS64 and VISWS */ + /* SGI Linux logo on MIPS/MIPS64 */ logo = &logo_sgi_clut224; #endif #ifdef CONFIG_LOGO_SUN_CLUT224 diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c deleted file mode 100644 index bc74d040899..00000000000 --- a/drivers/video/sgivwfb.c +++ /dev/null @@ -1,889 +0,0 @@ -/* - * linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Jeffrey Newquist, newquist@engr.sgi.som - * - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/errno.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> - -#include <asm/io.h> -#include <asm/mtrr.h> -#include <asm/visws/sgivw.h> - -#define INCLUDE_TIMING_TABLE_DATA -#define DBE_REG_BASE par->regs -#include <video/sgivw.h> - -struct sgivw_par { - struct asregs *regs; - u32 cmap_fifo; - u_long timing_num; -}; - -#define FLATPANEL_SGI_1600SW 5 - -/* - * RAM we reserve for the frame buffer. This defines the maximum screen - * size - * - * The default can be overridden if the driver is compiled as a module - */ - -static int ypan = 0; -static int ywrap = 0; - -static int flatpanel_id = -1; - -static struct fb_fix_screeninfo sgivwfb_fix = { - .id = "SGI Vis WS FB", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_PSEUDOCOLOR, - .mmio_start = DBE_REG_PHYS, - .mmio_len = DBE_REG_SIZE, - .accel = FB_ACCEL_NONE, - .line_length = 640, -}; - -static struct fb_var_screeninfo sgivwfb_var = { - /* 640x480, 8 bpp */ - .xres = 640, - .yres = 480, - .xres_virtual = 640, - .yres_virtual = 480, - .bits_per_pixel = 8, - .red = { 0, 8, 0 }, - .green = { 0, 8, 0 }, - .blue = { 0, 8, 0 }, - .height = -1, - .width = -1, - .pixclock = 20000, - .left_margin = 64, - .right_margin = 64, - .upper_margin = 32, - .lower_margin = 32, - .hsync_len = 64, - .vsync_len = 2, - .vmode = FB_VMODE_NONINTERLACED -}; - -static struct fb_var_screeninfo sgivwfb_var1600sw = { - /* 1600x1024, 8 bpp */ - .xres = 1600, - .yres = 1024, - .xres_virtual = 1600, - .yres_virtual = 1024, - .bits_per_pixel = 8, - .red = { 0, 8, 0 }, - .green = { 0, 8, 0 }, - .blue = { 0, 8, 0 }, - .height = -1, - .width = -1, - .pixclock = 9353, - .left_margin = 20, - .right_margin = 30, - .upper_margin = 37, - .lower_margin = 3, - .hsync_len = 20, - .vsync_len = 3, - .vmode = FB_VMODE_NONINTERLACED -}; - -/* - * Interface used by the world - */ -int sgivwfb_init(void); - -static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int sgivwfb_set_par(struct fb_info *info); -static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, - u_int blue, u_int transp, - struct fb_info *info); -static int sgivwfb_mmap(struct fb_info *info, - struct vm_area_struct *vma); - -static struct fb_ops sgivwfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = sgivwfb_check_var, - .fb_set_par = sgivwfb_set_par, - .fb_setcolreg = sgivwfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = sgivwfb_mmap, -}; - -/* - * Internal routines - */ -static unsigned long bytes_per_pixel(int bpp) -{ - switch (bpp) { - case 8: - return 1; - case 16: - return 2; - case 32: - return 4; - default: - printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp); - return 0; - } -} - -static unsigned long get_line_length(int xres_virtual, int bpp) -{ - return (xres_virtual * bytes_per_pixel(bpp)); -} - -/* - * Function: dbe_TurnOffDma - * Parameters: (None) - * Description: This should turn off the monitor and dbe. This is used - * when switching between the serial console and the graphics - * console. - */ - -static void dbe_TurnOffDma(struct sgivw_par *par) -{ - unsigned int readVal; - int i; - - // Check to see if things are already turned off: - // 1) Check to see if dbe is not using the internal dotclock. - // 2) Check to see if the xy counter in dbe is already off. - - DBE_GETREG(ctrlstat, readVal); - if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2) - return; - - DBE_GETREG(vt_xy, readVal); - if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) - return; - - // Otherwise, turn off dbe - - DBE_GETREG(ovr_control, readVal); - SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0); - DBE_SETREG(ovr_control, readVal); - udelay(1000); - DBE_GETREG(frm_control, readVal); - SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0); - DBE_SETREG(frm_control, readVal); - udelay(1000); - DBE_GETREG(did_control, readVal); - SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0); - DBE_SETREG(did_control, readVal); - udelay(1000); - - // XXX HACK: - // - // This was necessary for GBE--we had to wait through two - // vertical retrace periods before the pixel DMA was - // turned off for sure. I've left this in for now, in - // case dbe needs it. - - for (i = 0; i < 10000; i++) { - DBE_GETREG(frm_inhwctrl, readVal); - if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == - 0) - udelay(10); - else { - DBE_GETREG(ovr_inhwctrl, readVal); - if (GET_DBE_FIELD - (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) - udelay(10); - else { - DBE_GETREG(did_inhwctrl, readVal); - if (GET_DBE_FIELD - (DID_INHWCTRL, DID_DMA_ENABLE, - readVal) == 0) - udelay(10); - else - break; - } - } - } -} - -/* - * Set the User Defined Part of the Display. Again if par use it to get - * real video mode. - */ -static int sgivwfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct sgivw_par *par = (struct sgivw_par *)info->par; - struct dbe_timing_info *timing; - u_long line_length; - u_long min_mode; - int req_dot; - int test_mode; - - /* - * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! - * as FB_VMODE_SMOOTH_XPAN is only used internally - */ - - if (var->vmode & FB_VMODE_CONUPDATE) { - var->vmode |= FB_VMODE_YWRAP; - var->xoffset = info->var.xoffset; - var->yoffset = info->var.yoffset; - } - - /* XXX FIXME - forcing var's */ - var->xoffset = 0; - var->yoffset = 0; - - /* Limit bpp to 8, 16, and 32 */ - if (var->bits_per_pixel <= 8) - var->bits_per_pixel = 8; - else if (var->bits_per_pixel <= 16) - var->bits_per_pixel = 16; - else if (var->bits_per_pixel <= 32) - var->bits_per_pixel = 32; - else - return -EINVAL; - - var->grayscale = 0; /* No grayscale for now */ - - /* determine valid resolution and timing */ - for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) { - if (dbeVTimings[min_mode].width >= var->xres && - dbeVTimings[min_mode].height >= var->yres) - break; - } - - if (min_mode == ARRAY_SIZE(dbeVTimings)) - return -EINVAL; /* Resolution to high */ - - /* XXX FIXME - should try to pick best refresh rate */ - /* for now, pick closest dot-clock within 3MHz */ - req_dot = PICOS2KHZ(var->pixclock); - printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", - var->pixclock, req_dot); - test_mode = min_mode; - while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) { - if (dbeVTimings[test_mode].cfreq + 3000 > req_dot) - break; - test_mode++; - } - if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width) - test_mode--; - min_mode = test_mode; - timing = &dbeVTimings[min_mode]; - printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq); - - /* Adjust virtual resolution, if necessary */ - if (var->xres > var->xres_virtual || (!ywrap && !ypan)) - var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual || (!ywrap && !ypan)) - var->yres_virtual = var->yres; - - /* - * Memory limit - */ - line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); - if (line_length * var->yres_virtual > sgivwfb_mem_size) - return -ENOMEM; /* Virtual resolution to high */ - - info->fix.line_length = line_length; - - switch (var->bits_per_pixel) { - case 8: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 16: /* RGBA 5551 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 6; - var->green.length = 5; - var->blue.offset = 1; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 32: /* RGB 8888 */ - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - - /* set video timing information */ - var->pixclock = KHZ2PICOS(timing->cfreq); - var->left_margin = timing->htotal - timing->hsync_end; - var->right_margin = timing->hsync_start - timing->width; - var->upper_margin = timing->vtotal - timing->vsync_end; - var->lower_margin = timing->vsync_start - timing->height; - var->hsync_len = timing->hsync_end - timing->hsync_start; - var->vsync_len = timing->vsync_end - timing->vsync_start; - - /* Ouch. This breaks the rules but timing_num is only important if you - * change a video mode */ - par->timing_num = min_mode; - - printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n", - var->xres, var->yres, var->bits_per_pixel); - printk(KERN_INFO " vxres=%d vyres=%d\n", var->xres_virtual, - var->yres_virtual); - return 0; -} - -/* - * Setup flatpanel related registers. - */ -static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming) -{ - int fp_wid, fp_hgt, fp_vbs, fp_vbe; - u32 outputVal = 0; - - SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, - (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1); - SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, - (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1); - DBE_SETREG(vt_flags, outputVal); - - /* Turn on the flat panel */ - switch (flatpanel_id) { - case FLATPANEL_SGI_1600SW: - fp_wid = 1600; - fp_hgt = 1024; - fp_vbs = 0; - fp_vbe = 1600; - currentTiming->pll_m = 4; - currentTiming->pll_n = 1; - currentTiming->pll_p = 0; - break; - default: - fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff; - } - - outputVal = 0; - SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs); - SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe); - DBE_SETREG(fp_de, outputVal); - outputVal = 0; - SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid); - DBE_SETREG(fp_hdrv, outputVal); - outputVal = 0; - SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1); - SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1); - DBE_SETREG(fp_vdrv, outputVal); -} - -/* - * Set the hardware according to 'par'. - */ -static int sgivwfb_set_par(struct fb_info *info) -{ - struct sgivw_par *par = info->par; - int i, j, htmp, temp; - u32 readVal, outputVal; - int wholeTilesX, maxPixelsPerTileX; - int frmWrite1, frmWrite2, frmWrite3b; - struct dbe_timing_info *currentTiming; /* Current Video Timing */ - int xpmax, ypmax; // Monitor resolution - int bytesPerPixel; // Bytes per pixel - - currentTiming = &dbeVTimings[par->timing_num]; - bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel); - xpmax = currentTiming->width; - ypmax = currentTiming->height; - - /* dbe_InitGraphicsBase(); */ - /* Turn on dotclock PLL */ - DBE_SETREG(ctrlstat, 0x20000000); - - dbe_TurnOffDma(par); - - /* dbe_CalculateScreenParams(); */ - maxPixelsPerTileX = 512 / bytesPerPixel; - wholeTilesX = xpmax / maxPixelsPerTileX; - if (wholeTilesX * maxPixelsPerTileX < xpmax) - wholeTilesX++; - - printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n", - maxPixelsPerTileX, wholeTilesX); - - /* dbe_InitGammaMap(); */ - udelay(10); - - for (i = 0; i < 256; i++) { - DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); - } - - /* dbe_TurnOn(); */ - DBE_GETREG(vt_xy, readVal); - if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) { - DBE_SETREG(vt_xy, 0x00000000); - udelay(1); - } else - dbe_TurnOffDma(par); - - /* dbe_Initdbe(); */ - for (i = 0; i < 256; i++) { - for (j = 0; j < 100; j++) { - DBE_GETREG(cm_fifo, readVal); - if (readVal != 0x00000000) - break; - else - udelay(10); - } - - // DBE_ISETREG(cmap, i, 0x00000000); - DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24)); - } - - /* dbe_InitFramebuffer(); */ - frmWrite1 = 0; - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, - wholeTilesX); - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0); - - switch (bytesPerPixel) { - case 1: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_8); - break; - case 2: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_16); - break; - case 4: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_32); - break; - } - - frmWrite2 = 0; - SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); - - // Tell dbe about the framebuffer location and type - // XXX What format is the FRM_TILE_PTR?? 64K aligned address? - frmWrite3b = 0; - SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, - sgivwfb_mem_phys >> 9); - SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); - SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1); - - /* Initialize DIDs */ - - outputVal = 0; - switch (bytesPerPixel) { - case 1: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8); - break; - case 2: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5); - break; - case 4: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8); - break; - } - SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH); - - for (i = 0; i < 32; i++) { - DBE_ISETREG(mode_regs, i, outputVal); - } - - /* dbe_InitTiming(); */ - DBE_SETREG(vt_intr01, 0xffffffff); - DBE_SETREG(vt_intr23, 0xffffffff); - - DBE_GETREG(dotclock, readVal); - DBE_SETREG(dotclock, readVal & 0xffff); - - DBE_SETREG(vt_xymax, 0x00000000); - outputVal = 0; - SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, - currentTiming->vsync_start); - SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, - currentTiming->vsync_end); - DBE_SETREG(vt_vsync, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, - currentTiming->hsync_start); - SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, - currentTiming->hsync_end); - DBE_SETREG(vt_hsync, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vblank, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, - currentTiming->hblank_start); - SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, - currentTiming->hblank_end - 3); - DBE_SETREG(vt_hblank, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vcmap, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, - currentTiming->hblank_start); - SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, - currentTiming->hblank_end - 3); - DBE_SETREG(vt_hcmap, outputVal); - - if (flatpanel_id != -1) - sgivwfb_setup_flatpanel(par, currentTiming); - - outputVal = 0; - temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; - if (temp > 0) - temp = -temp; - - SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp); - if (currentTiming->hblank_end >= 20) - SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, - currentTiming->hblank_end - 20); - else - SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, - currentTiming->htotal - (20 - - currentTiming-> - hblank_end)); - DBE_SETREG(did_start_xy, outputVal); - - outputVal = 0; - SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, - (u32) (temp + 1)); - if (currentTiming->hblank_end >= DBE_CRS_MAGIC) - SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, - currentTiming->hblank_end - DBE_CRS_MAGIC); - else - SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, - currentTiming->htotal - (DBE_CRS_MAGIC - - currentTiming-> - hblank_end)); - DBE_SETREG(crs_start_xy, outputVal); - - outputVal = 0; - SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp); - SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal, - currentTiming->hblank_end - 4); - DBE_SETREG(vc_start_xy, outputVal); - - DBE_SETREG(frm_size_tile, frmWrite1); - DBE_SETREG(frm_size_pixel, frmWrite2); - - outputVal = 0; - SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1); - SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1); - SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); - SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1); - DBE_SETREG(dotclock, outputVal); - - udelay(11 * 1000); - - DBE_SETREG(vt_vpixen, 0xffffff); - DBE_SETREG(vt_hpixen, 0xffffff); - - outputVal = 0; - SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); - SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); - DBE_SETREG(vt_xymax, outputVal); - - outputVal = frmWrite1; - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); - DBE_SETREG(frm_size_tile, outputVal); - DBE_SETREG(frm_size_tile, frmWrite1); - - outputVal = 0; - SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); - DBE_SETREG(ovr_width_tile, outputVal); - DBE_SETREG(ovr_width_tile, 0); - - DBE_SETREG(frm_control, frmWrite3b); - DBE_SETREG(did_control, 0); - - // Wait for dbe to take frame settings - for (i = 0; i < 100000; i++) { - DBE_GETREG(frm_inhwctrl, readVal); - if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != - 0) - break; - else - udelay(1); - } - - if (i == 100000) - printk(KERN_INFO - "sgivwfb: timeout waiting for frame DMA enable.\n"); - - outputVal = 0; - htmp = currentTiming->hblank_end - 19; - if (htmp < 0) - htmp += currentTiming->htotal; /* allow blank to wrap around */ - SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); - SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, - ((htmp + currentTiming->width - - 2) % currentTiming->htotal)); - DBE_SETREG(vt_hpixen, outputVal); - - outputVal = 0; - SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vpixen, outputVal); - - // Turn off mouse cursor - par->regs->crs_ctl = 0; - - // XXX What's this section for?? - DBE_GETREG(ctrlstat, readVal); - readVal &= 0x02000000; - - if (readVal != 0) { - DBE_SETREG(ctrlstat, 0x30000000); - } - return 0; -} - -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, - u_int blue, u_int transp, - struct fb_info *info) -{ - struct sgivw_par *par = (struct sgivw_par *) info->par; - - if (regno > 255) - return 1; - red >>= 8; - green >>= 8; - blue >>= 8; - - /* wait for the color map FIFO to have a free entry */ - while (par->cmap_fifo == 0) - par->cmap_fifo = par->regs->cm_fifo; - - par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); - par->cmap_fifo--; /* assume FIFO is filling up */ - return 0; -} - -static int sgivwfb_mmap(struct fb_info *info, - struct vm_area_struct *vma) -{ - int r; - - pgprot_val(vma->vm_page_prot) = - pgprot_val(vma->vm_page_prot) | _PAGE_PCD; - - r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size); - - printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", - sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start); - - return r; -} - -int __init sgivwfb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "monitor:", 8)) { - if (!strncmp(this_opt + 8, "crt", 3)) - flatpanel_id = -1; - else if (!strncmp(this_opt + 8, "1600sw", 6)) - flatpanel_id = FLATPANEL_SGI_1600SW; - } - } - return 0; -} - -/* - * Initialisation - */ -static int sgivwfb_probe(struct platform_device *dev) -{ - struct sgivw_par *par; - struct fb_info *info; - char *monitor; - - info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev); - if (!info) - return -ENOMEM; - par = info->par; - - if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) { - printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n"); - framebuffer_release(info); - return -EBUSY; - } - - par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE); - if (!par->regs) { - printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n"); - goto fail_ioremap_regs; - } - - mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1); - - sgivwfb_fix.smem_start = sgivwfb_mem_phys; - sgivwfb_fix.smem_len = sgivwfb_mem_size; - sgivwfb_fix.ywrapstep = ywrap; - sgivwfb_fix.ypanstep = ypan; - - info->fix = sgivwfb_fix; - - switch (flatpanel_id) { - case FLATPANEL_SGI_1600SW: - info->var = sgivwfb_var1600sw; - monitor = "SGI 1600SW flatpanel"; - break; - default: - info->var = sgivwfb_var; - monitor = "CRT"; - } - - printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor); - - info->fbops = &sgivwfb_ops; - info->pseudo_palette = (void *) (par + 1); - info->flags = FBINFO_DEFAULT; - - info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size); - if (!info->screen_base) { - printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n"); - goto fail_ioremap_fbmem; - } - - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) - goto fail_color_map; - - if (register_framebuffer(info) < 0) { - printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n"); - goto fail_register_framebuffer; - } - - platform_set_drvdata(dev, info); - - fb_info(info, "SGI DBE frame buffer device, using %ldK of video memory at %#lx\n", - sgivwfb_mem_size >> 10, sgivwfb_mem_phys); - return 0; - -fail_register_framebuffer: - fb_dealloc_cmap(&info->cmap); -fail_color_map: - iounmap((char *) info->screen_base); -fail_ioremap_fbmem: - iounmap(par->regs); -fail_ioremap_regs: - release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); - framebuffer_release(info); - return -ENXIO; -} - -static int sgivwfb_remove(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - - if (info) { - struct sgivw_par *par = info->par; - - unregister_framebuffer(info); - dbe_TurnOffDma(par); - iounmap(par->regs); - iounmap(info->screen_base); - release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } - return 0; -} - -static struct platform_driver sgivwfb_driver = { - .probe = sgivwfb_probe, - .remove = sgivwfb_remove, - .driver = { - .name = "sgivwfb", - }, -}; - -static struct platform_device *sgivwfb_device; - -int __init sgivwfb_init(void) -{ - int ret; - -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("sgivwfb", &option)) - return -ENODEV; - sgivwfb_setup(option); -#endif - ret = platform_driver_register(&sgivwfb_driver); - if (!ret) { - sgivwfb_device = platform_device_alloc("sgivwfb", 0); - if (sgivwfb_device) { - ret = platform_device_add(sgivwfb_device); - } else - ret = -ENOMEM; - if (ret) { - platform_driver_unregister(&sgivwfb_driver); - platform_device_put(sgivwfb_device); - } - } - return ret; -} - -module_init(sgivwfb_init); - -#ifdef MODULE -MODULE_LICENSE("GPL"); - -static void __exit sgivwfb_exit(void) -{ - platform_device_unregister(sgivwfb_device); - platform_driver_unregister(&sgivwfb_driver); -} - -module_exit(sgivwfb_exit); - -#endif /* MODULE */ diff --git a/include/video/sgivw.h b/include/video/sgivw.h deleted file mode 100644 index f6aa5692e74..00000000000 --- a/include/video/sgivw.h +++ /dev/null @@ -1,681 +0,0 @@ -/* - * linux/drivers/video/sgivw.h -- SGI DBE frame buffer device header - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Jeffrey Newquist, newquist@engr.sgi.som - * - * 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. - */ - -#ifndef __SGIVWFB_H__ -#define __SGIVWFB_H__ - -#define DBE_GETREG(reg, dest) ((dest) = DBE_REG_BASE->reg) -#define DBE_SETREG(reg, src) DBE_REG_BASE->reg = (src) -#define DBE_IGETREG(reg, idx, dest) ((dest) = DBE_REG_BASE->reg[idx]) -#define DBE_ISETREG(reg, idx, src) (DBE_REG_BASE->reg[idx] = (src)) - -#define MASK(msb, lsb) ( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) ) -#define GET(v, msb, lsb) ( ((u32)(v) & MASK(msb,lsb)) >> (lsb) ) -#define SET(v, f, msb, lsb) ( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) ) - -#define GET_DBE_FIELD(reg, field, v) GET((v), DBE_##reg##_##field##_MSB, DBE_##reg##_##field##_LSB) -#define SET_DBE_FIELD(reg, field, v, f) SET((v), (f), DBE_##reg##_##field##_MSB, DBE_##reg##_##field##_LSB) - -/* NOTE: All loads/stores must be 32 bits and uncached */ - -#define DBE_REG_PHYS 0xd0000000 -#define DBE_REG_SIZE 0x01000000 - -struct asregs { - volatile u32 ctrlstat; /* 0x000000 general control */ - volatile u32 dotclock; /* 0x000004 dot clock PLL control */ - volatile u32 i2c; /* 0x000008 crt I2C control */ - volatile u32 sysclk; /* 0x00000c system clock PLL control */ - volatile u32 i2cfp; /* 0x000010 flat panel I2C control */ - volatile u32 id; /* 0x000014 device id/chip revision */ - volatile u32 config; /* 0x000018 power on configuration */ - volatile u32 bist; /* 0x00001c internal bist status */ - - char _pad0[ 0x010000 - 0x000020 ]; - - volatile u32 vt_xy; /* 0x010000 current dot coords */ - volatile u32 vt_xymax; /* 0x010004 maximum dot coords */ - volatile u32 vt_vsync; /* 0x010008 vsync on/off */ - volatile u32 vt_hsync; /* 0x01000c hsync on/off */ - volatile u32 vt_vblank; /* 0x010010 vblank on/off */ - volatile u32 vt_hblank; /* 0x010014 hblank on/off */ - volatile u32 vt_flags; /* 0x010018 polarity of vt signals */ - volatile u32 vt_f2rf_lock; /* 0x01001c f2rf & framelck y coord */ - volatile u32 vt_intr01; /* 0x010020 intr 0,1 y coords */ - volatile u32 vt_intr23; /* 0x010024 intr 2,3 y coords */ - volatile u32 fp_hdrv; /* 0x010028 flat panel hdrv on/off */ - volatile u32 fp_vdrv; /* 0x01002c flat panel vdrv on/off */ - volatile u32 fp_de; /* 0x010030 flat panel de on/off */ - volatile u32 vt_hpixen; /* 0x010034 intrnl horiz pixel on/off*/ - volatile u32 vt_vpixen; /* 0x010038 intrnl vert pixel on/off */ - volatile u32 vt_hcmap; /* 0x01003c cmap write (horiz) */ - volatile u32 vt_vcmap; /* 0x010040 cmap write (vert) */ - volatile u32 did_start_xy; /* 0x010044 eol/f did/xy reset val */ - volatile u32 crs_start_xy; /* 0x010048 eol/f crs/xy reset val */ - volatile u32 vc_start_xy; /* 0x01004c eol/f vc/xy reset val */ - - char _pad1[ 0x020000 - 0x010050 ]; - - volatile u32 ovr_width_tile; /* 0x020000 overlay plane ctrl 0 */ - volatile u32 ovr_inhwctrl; /* 0x020004 overlay plane ctrl 1 */ - volatile u32 ovr_control; /* 0x020008 overlay plane ctrl 1 */ - - char _pad2[ 0x030000 - 0x02000C ]; - - volatile u32 frm_size_tile; /* 0x030000 normal plane ctrl 0 */ - volatile u32 frm_size_pixel; /* 0x030004 normal plane ctrl 1 */ - volatile u32 frm_inhwctrl; /* 0x030008 normal plane ctrl 2 */ - volatile u32 frm_control; /* 0x03000C normal plane ctrl 3 */ - - char _pad3[ 0x040000 - 0x030010 ]; - - volatile u32 did_inhwctrl; /* 0x040000 DID control */ - volatile u32 did_control; /* 0x040004 DID shadow */ - - char _pad4[ 0x048000 - 0x040008 ]; - - volatile u32 mode_regs[32]; /* 0x048000 - 0x04807c WID table */ - - char _pad5[ 0x050000 - 0x048080 ]; - - volatile u32 cmap[6144]; /* 0x050000 - 0x055ffc color map */ - - char _pad6[ 0x058000 - 0x056000 ]; - - volatile u32 cm_fifo; /* 0x058000 color map fifo status */ - - char _pad7[ 0x060000 - 0x058004 ]; - - volatile u32 gmap[256]; /* 0x060000 - 0x0603fc gamma map */ - - char _pad8[ 0x068000 - 0x060400 ]; - - volatile u32 gmap10[1024]; /* 0x068000 - 0x068ffc gamma map */ - - char _pad9[ 0x070000 - 0x069000 ]; - - volatile u32 crs_pos; /* 0x070000 cusror control 0 */ - volatile u32 crs_ctl; /* 0x070004 cusror control 1 */ - volatile u32 crs_cmap[3]; /* 0x070008 - 0x070010 crs cmap */ - - char _pad10[ 0x078000 - 0x070014 ]; - - volatile u32 crs_glyph[64]; /* 0x078000 - 0x0780fc crs glyph */ - - char _pad11[ 0x080000 - 0x078100 ]; - - volatile u32 vc_0; /* 0x080000 video capture crtl 0 */ - volatile u32 vc_1; /* 0x080004 video capture crtl 1 */ - volatile u32 vc_2; /* 0x080008 video capture crtl 2 */ - volatile u32 vc_3; /* 0x08000c video capture crtl 3 */ - volatile u32 vc_4; /* 0x080010 video capture crtl 3 */ - volatile u32 vc_5; /* 0x080014 video capture crtl 3 */ - volatile u32 vc_6; /* 0x080018 video capture crtl 3 */ - volatile u32 vc_7; /* 0x08001c video capture crtl 3 */ - volatile u32 vc_8; /* 0x08000c video capture crtl 3 */ -}; - -/* Bit mask information */ - -#define DBE_CTRLSTAT_CHIPID_MSB 3 -#define DBE_CTRLSTAT_CHIPID_LSB 0 -#define DBE_CTRLSTAT_SENSE_N_MSB 4 -#define DBE_CTRLSTAT_SENSE_N_LSB 4 -#define DBE_CTRLSTAT_PCLKSEL_MSB 29 -#define DBE_CTRLSTAT_PCLKSEL_LSB 28 - -#define DBE_DOTCLK_M_MSB 7 -#define DBE_DOTCLK_M_LSB 0 -#define DBE_DOTCLK_N_MSB 13 -#define DBE_DOTCLK_N_LSB 8 -#define DBE_DOTCLK_P_MSB 15 -#define DBE_DOTCLK_P_LSB 14 -#define DBE_DOTCLK_RUN_MSB 20 -#define DBE_DOTCLK_RUN_LSB 20 - -#define DBE_VT_XY_VT_FREEZE_MSB 31 -#define DBE_VT_XY_VT_FREEZE_LSB 31 - -#define DBE_FP_VDRV_FP_VDRV_ON_MSB 23 -#define DBE_FP_VDRV_FP_VDRV_ON_LSB 12 -#define DBE_FP_VDRV_FP_VDRV_OFF_MSB 11 -#define DBE_FP_VDRV_FP_VDRV_OFF_LSB 0 - -#define DBE_FP_HDRV_FP_HDRV_ON_MSB 23 -#define DBE_FP_HDRV_FP_HDRV_ON_LSB 12 -#define DBE_FP_HDRV_FP_HDRV_OFF_MSB 11 -#define DBE_FP_HDRV_FP_HDRV_OFF_LSB 0 - -#define DBE_FP_DE_FP_DE_ON_MSB 23 -#define DBE_FP_DE_FP_DE_ON_LSB 12 -#define DBE_FP_DE_FP_DE_OFF_MSB 11 -#define DBE_FP_DE_FP_DE_OFF_LSB 0 - -#define DBE_VT_VSYNC_VT_VSYNC_ON_MSB 23 -#define DBE_VT_VSYNC_VT_VSYNC_ON_LSB 12 -#define DBE_VT_VSYNC_VT_VSYNC_OFF_MSB 11 -#define DBE_VT_VSYNC_VT_VSYNC_OFF_LSB 0 - -#define DBE_VT_HSYNC_VT_HSYNC_ON_MSB 23 -#define DBE_VT_HSYNC_VT_HSYNC_ON_LSB 12 -#define DBE_VT_HSYNC_VT_HSYNC_OFF_MSB 11 -#define DBE_VT_HSYNC_VT_HSYNC_OFF_LSB 0 - -#define DBE_VT_VBLANK_VT_VBLANK_ON_MSB 23 -#define DBE_VT_VBLANK_VT_VBLANK_ON_LSB 12 -#define DBE_VT_VBLANK_VT_VBLANK_OFF_MSB 11 -#define DBE_VT_VBLANK_VT_VBLANK_OFF_LSB 0 - -#define DBE_VT_HBLANK_VT_HBLANK_ON_MSB 23 -#define DBE_VT_HBLANK_VT_HBLANK_ON_LSB 12 -#define DBE_VT_HBLANK_VT_HBLANK_OFF_MSB 11 -#define DBE_VT_HBLANK_VT_HBLANK_OFF_LSB 0 - -#define DBE_VT_FLAGS_VDRV_INVERT_MSB 0 -#define DBE_VT_FLAGS_VDRV_INVERT_LSB 0 -#define DBE_VT_FLAGS_HDRV_INVERT_MSB 2 -#define DBE_VT_FLAGS_HDRV_INVERT_LSB 2 - -#define DBE_VT_VCMAP_VT_VCMAP_ON_MSB 23 -#define DBE_VT_VCMAP_VT_VCMAP_ON_LSB 12 -#define DBE_VT_VCMAP_VT_VCMAP_OFF_MSB 11 -#define DBE_VT_VCMAP_VT_VCMAP_OFF_LSB 0 - -#define DBE_VT_HCMAP_VT_HCMAP_ON_MSB 23 -#define DBE_VT_HCMAP_VT_HCMAP_ON_LSB 12 -#define DBE_VT_HCMAP_VT_HCMAP_OFF_MSB 11 -#define DBE_VT_HCMAP_VT_HCMAP_OFF_LSB 0 - -#define DBE_VT_XYMAX_VT_MAXX_MSB 11 -#define DBE_VT_XYMAX_VT_MAXX_LSB 0 -#define DBE_VT_XYMAX_VT_MAXY_MSB 23 -#define DBE_VT_XYMAX_VT_MAXY_LSB 12 - -#define DBE_VT_HPIXEN_VT_HPIXEN_ON_MSB 23 -#define DBE_VT_HPIXEN_VT_HPIXEN_ON_LSB 12 -#define DBE_VT_HPIXEN_VT_HPIXEN_OFF_MSB 11 -#define DBE_VT_HPIXEN_VT_HPIXEN_OFF_LSB 0 - -#define DBE_VT_VPIXEN_VT_VPIXEN_ON_MSB 23 -#define DBE_VT_VPIXEN_VT_VPIXEN_ON_LSB 12 -#define DBE_VT_VPIXEN_VT_VPIXEN_OFF_MSB 11 -#define DBE_VT_VPIXEN_VT_VPIXEN_OFF_LSB 0 - -#define DBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB 0 -#define DBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB 0 - -#define DBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB 0 -#define DBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB 0 - -#define DBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB 13 -#define DBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB 13 - -#define DBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB 0 -#define DBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB 0 -#define DBE_FRM_CONTROL_FRM_TILE_PTR_MSB 31 -#define DBE_FRM_CONTROL_FRM_TILE_PTR_LSB 9 -#define DBE_FRM_CONTROL_FRM_LINEAR_MSB 1 -#define DBE_FRM_CONTROL_FRM_LINEAR_LSB 1 - -#define DBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB 0 -#define DBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB 0 - -#define DBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB 12 -#define DBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB 5 -#define DBE_FRM_SIZE_TILE_FRM_RHS_MSB 4 -#define DBE_FRM_SIZE_TILE_FRM_RHS_LSB 0 -#define DBE_FRM_SIZE_TILE_FRM_DEPTH_MSB 14 -#define DBE_FRM_SIZE_TILE_FRM_DEPTH_LSB 13 -#define DBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB 15 -#define DBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB 15 - -#define DBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB 31 -#define DBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB 16 - -#define DBE_DID_CONTROL_DID_DMA_ENABLE_MSB 0 -#define DBE_DID_CONTROL_DID_DMA_ENABLE_LSB 0 -#define DBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB 0 -#define DBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB 0 - -#define DBE_DID_START_XY_DID_STARTY_MSB 23 -#define DBE_DID_START_XY_DID_STARTY_LSB 12 -#define DBE_DID_START_XY_DID_STARTX_MSB 11 -#define DBE_DID_START_XY_DID_STARTX_LSB 0 - -#define DBE_CRS_START_XY_CRS_STARTY_MSB 23 -#define DBE_CRS_START_XY_CRS_STARTY_LSB 12 -#define DBE_CRS_START_XY_CRS_STARTX_MSB 11 -#define DBE_CRS_START_XY_CRS_STARTX_LSB 0 - -#define DBE_WID_TYP_MSB 4 -#define DBE_WID_TYP_LSB 2 -#define DBE_WID_BUF_MSB 1 -#define DBE_WID_BUF_LSB 0 - -#define DBE_VC_START_XY_VC_STARTY_MSB 23 -#define DBE_VC_START_XY_VC_STARTY_LSB 12 -#define DBE_VC_START_XY_VC_STARTX_MSB 11 -#define DBE_VC_START_XY_VC_STARTX_LSB 0 - -/* Constants */ - -#define DBE_FRM_DEPTH_8 0 -#define DBE_FRM_DEPTH_16 1 -#define DBE_FRM_DEPTH_32 2 - -#define DBE_CMODE_I8 0 -#define DBE_CMODE_I12 1 -#define DBE_CMODE_RG3B2 2 -#define DBE_CMODE_RGB4 3 -#define DBE_CMODE_ARGB5 4 -#define DBE_CMODE_RGB8 5 -#define DBE_CMODE_RGBA5 6 -#define DBE_CMODE_RGB10 7 - -#define DBE_BMODE_BOTH 3 - -#define DBE_CRS_MAGIC 54 - -#define DBE_CLOCK_REF_KHZ 27000 - -/* Config Register (DBE Only) Definitions */ - -#define DBE_CONFIG_VDAC_ENABLE 0x00000001 -#define DBE_CONFIG_VDAC_GSYNC 0x00000002 -#define DBE_CONFIG_VDAC_PBLANK 0x00000004 -#define DBE_CONFIG_FPENABLE 0x00000008 -#define DBE_CONFIG_LENDIAN 0x00000020 -#define DBE_CONFIG_TILEHIST 0x00000040 -#define DBE_CONFIG_EXT_ADDR 0x00000080 - -#define DBE_CONFIG_FBDEV ( DBE_CONFIG_VDAC_ENABLE | \ - DBE_CONFIG_VDAC_GSYNC | \ - DBE_CONFIG_VDAC_PBLANK | \ - DBE_CONFIG_LENDIAN | \ - DBE_CONFIG_EXT_ADDR ) - -/* - * Available Video Timings and Corresponding Indices - */ - -typedef enum { - DBE_VT_640_480_60, - - DBE_VT_800_600_60, - DBE_VT_800_600_75, - DBE_VT_800_600_120, - - DBE_VT_1024_768_50, - DBE_VT_1024_768_60, - DBE_VT_1024_768_75, - DBE_VT_1024_768_85, - DBE_VT_1024_768_120, - - DBE_VT_1280_1024_50, - DBE_VT_1280_1024_60, - DBE_VT_1280_1024_75, - DBE_VT_1280_1024_85, - - DBE_VT_1600_1024_53, - DBE_VT_1600_1024_60, - - DBE_VT_1600_1200_50, - DBE_VT_1600_1200_60, - DBE_VT_1600_1200_75, - - DBE_VT_1920_1080_50, - DBE_VT_1920_1080_60, - DBE_VT_1920_1080_72, - - DBE_VT_1920_1200_50, - DBE_VT_1920_1200_60, - DBE_VT_1920_1200_66, - - DBE_VT_UNKNOWN -} dbe_timing_t; - - - -/* - * Crime Video Timing Data Structure - */ - -struct dbe_timing_info -{ - dbe_timing_t type; - int flags; - short width; /* Monitor resolution */ - short height; - int fields_sec; /* fields/sec (Hz -3 dec. places */ - int cfreq; /* pixel clock frequency (MHz -3 dec. places) */ - short htotal; /* Horizontal total pixels */ - short hblank_start; /* Horizontal blank start */ - short hblank_end; /* Horizontal blank end */ - short hsync_start; /* Horizontal sync start */ - short hsync_end; /* Horizontal sync end */ - short vtotal; /* Vertical total lines */ - short vblank_start; /* Vertical blank start */ - short vblank_end; /* Vertical blank end */ - short vsync_start; /* Vertical sync start */ - short vsync_end; /* Vertical sync end */ - short pll_m; /* PLL M parameter */ - short pll_n; /* PLL P parameter */ - short pll_p; /* PLL N parameter */ -}; - -/* Defines for dbe_vof_info_t flags */ - -#define DBE_VOF_UNKNOWNMON 1 -#define DBE_VOF_STEREO 2 -#define DBE_VOF_DO_GENSYNC 4 /* enable incoming sync */ -#define DBE_VOF_SYNC_ON_GREEN 8 /* sync on green */ -#define DBE_VOF_FLATPANEL 0x1000 /* FLATPANEL Timing */ -#define DBE_VOF_MAGICKEY 0x2000 /* Backdoor key */ - -/* - * DBE Timing Tables - */ - -#ifdef INCLUDE_TIMING_TABLE_DATA -struct dbe_timing_info dbeVTimings[] = { - { - DBE_VT_640_480_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 640, 480, 59940, 25175, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 800, 640, 800, 656, 752, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 525, 480, 525, 490, 492, - /* pll_m, pll_n, pll_p */ - 15, 2, 3 - }, - - { - DBE_VT_800_600_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 800, 600, 60317, 40000, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1056, 800, 1056, 840, 968, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 628, 600, 628, 601, 605, - /* pll_m, pll_n, pll_p */ - 3, 1, 1 - }, - - { - DBE_VT_800_600_75, - /* flags, width, height, fields_sec, cfreq */ - 0, 800, 600, 75000, 49500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1056, 800, 1056, 816, 896, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 625, 600, 625, 601, 604, - /* pll_m, pll_n, pll_p */ - 11, 3, 1 - }, - - { - DBE_VT_800_600_120, - /* flags, width, height, fields_sec, cfreq */ - DBE_VOF_STEREO, 800, 600, 119800, 82978, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1040, 800, 1040, 856, 976, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 666, 600, 666, 637, 643, - /* pll_m, pll_n, pll_p */ - 31, 5, 1 - }, - - { - DBE_VT_1024_768_50, - /* flags, width, height, fields_sec, cfreq */ - 0, 1024, 768, 50000, 54163, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1344, 1024, 1344, 1048, 1184, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 806, 768, 806, 771, 777, - /* pll_m, pll_n, pll_p */ - 4, 1, 1 - }, - - { - DBE_VT_1024_768_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 1024, 768, 60004, 65000, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1344, 1024, 1344, 1048, 1184, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 806, 768, 806, 771, 777, - /* pll_m, pll_n, pll_p */ - 12, 5, 0 - }, - - { - DBE_VT_1024_768_75, - /* flags, width, height, fields_sec, cfreq */ - 0, 1024, 768, 75029, 78750, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1312, 1024, 1312, 1040, 1136, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 800, 768, 800, 769, 772, - /* pll_m, pll_n, pll_p */ - 29, 5, 1 - }, - - { - DBE_VT_1024_768_85, - /* flags, width, height, fields_sec, cfreq */ - 0, 1024, 768, 84997, 94500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1376, 1024, 1376, 1072, 1168, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 808, 768, 808, 769, 772, - /* pll_m, pll_n, pll_p */ - 7, 2, 0 - }, - - { - DBE_VT_1024_768_120, - /* flags, width, height, fields_sec, cfreq */ - DBE_VOF_STEREO, 1024, 768, 119800, 133195, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1376, 1024, 1376, 1072, 1168, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 808, 768, 808, 769, 772, - /* pll_m, pll_n, pll_p */ - 5, 1, 0 - }, - - { - DBE_VT_1280_1024_50, - /* flags, width, height, fields_sec, cfreq */ - 0, 1280, 1024, 50000, 89460, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1680, 1280, 1680, 1360, 1480, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1065, 1024, 1065, 1027, 1030, - /* pll_m, pll_n, pll_p */ - 10, 3, 0 - }, - - { - DBE_VT_1280_1024_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 1280, 1024, 60020, 108000, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1688, 1280, 1688, 1328, 1440, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1066, 1024, 1066, 1025, 1028, - /* pll_m, pll_n, pll_p */ - 4, 1, 0 - }, - - { - DBE_VT_1280_1024_75, - /* flags, width, height, fields_sec, cfreq */ - 0, 1280, 1024, 75025, 135000, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1688, 1280, 1688, 1296, 1440, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1066, 1024, 1066, 1025, 1028, - /* pll_m, pll_n, pll_p */ - 5, 1, 0 - }, - - { - DBE_VT_1280_1024_85, - /* flags, width, height, fields_sec, cfreq */ - 0, 1280, 1024, 85024, 157500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1728, 1280, 1728, 1344, 1504, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1072, 1024, 1072, 1025, 1028, - /* pll_m, pll_n, pll_p */ - 29, 5, 0 - }, - - { - DBE_VT_1600_1024_53, - /* flags, width, height, fields_sec, cfreq */ - DBE_VOF_FLATPANEL | DBE_VOF_MAGICKEY, - 1600, 1024, 53000, 107447, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1900, 1600, 1900, 1630, 1730, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1067, 1024, 1067, 1027, 1030, - /* pll_m, pll_n, pll_p */ - 4, 1, 0 - }, - - { - DBE_VT_1600_1024_60, - /* flags, width, height, fields_sec, cfreq */ - DBE_VOF_FLATPANEL, 1600, 1024, 60000, 106913, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 1670, 1600, 1670, 1630, 1650, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1067, 1024, 1067, 1027, 1030, - /* pll_m, pll_n, pll_p */ - 4, 1, 0 - }, - - { - DBE_VT_1600_1200_50, - /* flags, width, height, fields_sec, cfreq */ - 0, 1600, 1200, 50000, 130500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2088, 1600, 2088, 1644, 1764, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1205, 1211, - /* pll_m, pll_n, pll_p */ - 24, 5, 0 - }, - - { - DBE_VT_1600_1200_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 1600, 1200, 59940, 162000, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2160, 1600, 2160, 1644, 1856, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1201, 1204, - /* pll_m, pll_n, pll_p */ - 6, 1, 0 - }, - - { - DBE_VT_1600_1200_75, - /* flags, width, height, fields_sec, cfreq */ - 0, 1600, 1200, 75000, 202500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2160, 1600, 2160, 1644, 1856, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1201, 1204, - /* pll_m, pll_n, pll_p */ - 15, 2, 0 - }, - - { - DBE_VT_1920_1080_50, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1080, 50000, 133200, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2368, 1920, 2368, 1952, 2096, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1125, 1080, 1125, 1083, 1086, - /* pll_m, pll_n, pll_p */ - 5, 1, 0 - }, - - { - DBE_VT_1920_1080_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1080, 59940, 159840, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2368, 1920, 2368, 1952, 2096, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1125, 1080, 1125, 1083, 1086, - /* pll_m, pll_n, pll_p */ - 6, 1, 0 - }, - - { - DBE_VT_1920_1080_72, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1080, 72000, 216023, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2560, 1920, 2560, 1968, 2184, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1172, 1080, 1172, 1083, 1086, - /* pll_m, pll_n, pll_p */ - 8, 1, 0 - }, - - { - DBE_VT_1920_1200_50, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1200, 50000, 161500, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2584, 1920, 2584, 1984, 2240, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1203, 1206, - /* pll_m, pll_n, pll_p */ - 6, 1, 0 - }, - - { - DBE_VT_1920_1200_60, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1200, 59940, 193800, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2584, 1920, 2584, 1984, 2240, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1203, 1206, - /* pll_m, pll_n, pll_p */ - 29, 4, 0 - }, - - { - DBE_VT_1920_1200_66, - /* flags, width, height, fields_sec, cfreq */ - 0, 1920, 1200, 66000, 213180, - /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ - 2584, 1920, 2584, 1984, 2240, - /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ - 1250, 1200, 1250, 1203, 1206, - /* pll_m, pll_n, pll_p */ - 8, 1, 0 - } -}; - -#endif // INCLUDE_TIMING_TABLE_DATA - -#endif // ! __SGIVWFB_H__ diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 1a964025443..48568fdf847 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -13,15 +13,6 @@ config SOUND_BCM_CS4297A note that CONFIG_KGDB should not be enabled at the same time, since it also attempts to use this UART port. -config SOUND_VWSND - tristate "SGI Visual Workstation Sound" - depends on X86_VISWS - help - Say Y or M if you have an SGI Visual Workstation and you want to be - able to use its on-board audio. Read - <file:Documentation/sound/oss/vwsnd> for more info on this driver's - capabilities. - config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" depends on (m || !STANDALONE) && ISA diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 77f21b68bf0..9bdbbde2173 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o -obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_DMASOUND) += dmasound/ diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c deleted file mode 100644 index a077e9c69a5..00000000000 --- a/sound/oss/vwsnd.c +++ /dev/null @@ -1,3506 +0,0 @@ -/* - * Sound driver for Silicon Graphics 320 and 540 Visual Workstations' - * onboard audio. See notes in Documentation/sound/oss/vwsnd . - * - * Copyright 1999 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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. - */ - -#undef VWSND_DEBUG /* define for debugging */ - -/* - * XXX to do - - * - * External sync. - * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational. - * Bug - if select() called before read(), pcm_setup() not called. - * Bug - output doesn't stop soon enough if process killed. - */ - -/* - * Things to test - - * - * Will readv/writev work? Write a test. - * - * insmod/rmmod 100 million times. - * - * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT - * rate). - * - * Concurrent threads banging on mixer simultaneously, both UP - * and SMP kernels. Especially, watch for thread A changing - * OUTSRC while thread B changes gain -- both write to the same - * ad1843 register. - * - * What happens if a client opens /dev/audio then forks? - * Do two procs have /dev/audio open? Test. - * - * Pump audio through the CD, MIC and line inputs and verify that - * they mix/mute into the output. - * - * Apps: - * amp - * mpg123 - * x11amp - * mxv - * kmedia - * esound - * need more input apps - * - * Run tests while bombarding with signals. setitimer(2) will do it... */ - -/* - * This driver is organized in nine sections. - * The nine sections are: - * - * debug stuff - * low level lithium access - * high level lithium access - * AD1843 access - * PCM I/O - * audio driver - * mixer driver - * probe/attach/unload - * initialization and loadable kernel module interface - * - * That is roughly the order of increasing abstraction, so forward - * dependencies are minimal. - */ - -/* - * Locking Notes - * - * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of - * open descriptors to this driver. They store it in vwsnd_use_count. - * The global device list, vwsnd_dev_list, is immutable when the IN_USE - * is true. - * - * devc->open_lock is a semaphore that is used to enforce the - * single reader/single writer rule for /dev/audio. The rule is - * that each device may have at most one reader and one writer. - * Open will block until the previous client has closed the - * device, unless O_NONBLOCK is specified. - * - * The semaphore devc->io_mutex serializes PCM I/O syscalls. This - * is unnecessary in Linux 2.2, because the kernel lock - * serializes read, write, and ioctl globally, but it's there, - * ready for the brave, new post-kernel-lock world. - * - * Locking between interrupt and baselevel is handled by the - * "lock" spinlock in vwsnd_port (one lock each for read and - * write). Each half holds the lock just long enough to see what - * area it owns and update its pointers. See pcm_output() and - * pcm_input() for most of the gory stuff. - * - * devc->mix_mutex serializes all mixer ioctls. This is also - * redundant because of the kernel lock. - * - * The lowest level lock is lith->lithium_lock. It is a - * spinlock which is held during the two-register tango of - * reading/writing an AD1843 register. See - * li_{read,write}_ad1843_reg(). - */ - -/* - * Sample Format Notes - * - * Lithium's DMA engine has two formats: 16-bit 2's complement - * and 8-bit unsigned . 16-bit transfers the data unmodified, 2 - * bytes per sample. 8-bit unsigned transfers 1 byte per sample - * and XORs each byte with 0x80. Lithium can input or output - * either mono or stereo in either format. - * - * The AD1843 has four formats: 16-bit 2's complement, 8-bit - * unsigned, 8-bit mu-Law and 8-bit A-Law. - * - * This driver supports five formats: AFMT_S8, AFMT_U8, - * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE. - * - * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and - * rely on Lithium's XOR to translate between U8 and S8. - * - * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR - * the 0x80 bit in software to compensate for Lithium's XOR. - * This happens in pcm_copy_{in,out}(). - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added some __init/__exit - */ - -#include <linux/module.h> -#include <linux/init.h> - -#include <linux/spinlock.h> -#include <linux/wait.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <linux/delay.h> - -#include <asm/visws/cobalt.h> - -#include "sound_config.h" - -static DEFINE_MUTEX(vwsnd_mutex); - -/*****************************************************************************/ -/* debug stuff */ - -#ifdef VWSND_DEBUG - -static int shut_up = 1; - -/* - * dbgassert - called when an assertion fails. - */ - -static void dbgassert(const char *fcn, int line, const char *expr) -{ - if (in_interrupt()) - panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n", - __FILE__, fcn, line, expr); - else { - int x; - printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n", - __FILE__, fcn, line, expr); - x = * (volatile int *) 0; /* force proc to exit */ - } -} - -/* - * Bunch of useful debug macros: - * - * ASSERT - print unless e nonzero (panic if in interrupt) - * DBGDO - include arbitrary code if debugging - * DBGX - debug print raw (w/o function name) - * DBGP - debug print w/ function name - * DBGE - debug print function entry - * DBGC - debug print function call - * DBGR - debug print function return - * DBGXV - debug print raw when verbose - * DBGPV - debug print when verbose - * DBGEV - debug print function entry when verbose - * DBGRV - debug print function return when verbose - */ - -#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__func__, __LINE__, #e)) -#define DBGDO(x) x -#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args)) -#define DBGP(fmt, args...) (DBGX("%s: " fmt, __func__ , ##args)) -#define DBGE(fmt, args...) (DBGX("%s" fmt, __func__ , ##args)) -#define DBGC(rtn) (DBGP("calling %s\n", rtn)) -#define DBGR() (DBGP("returning\n")) -#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args)) -#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args)) -#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args)) -#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn)) -#define DBGRV() (shut_up ? 0 : DBGR()) - -#else /* !VWSND_DEBUG */ - -#define ASSERT(e) ((void) 0) -#define DBGDO(x) /* don't */ -#define DBGX(fmt, args...) ((void) 0) -#define DBGP(fmt, args...) ((void) 0) -#define DBGE(fmt, args...) ((void) 0) -#define DBGC(rtn) ((void) 0) -#define DBGR() ((void) 0) -#define DBGPV(fmt, args...) ((void) 0) -#define DBGXV(fmt, args...) ((void) 0) -#define DBGEV(fmt, args...) ((void) 0) -#define DBGCV(rtn) ((void) 0) -#define DBGRV() ((void) 0) - -#endif /* !VWSND_DEBUG */ - -/*****************************************************************************/ -/* low level lithium access */ - -/* - * We need to talk to Lithium registers on three pages. Here are - * the pages' offsets from the base address (0xFF001000). - */ - -enum { - LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */ - LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */ - LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */ -}; - -/* low-level lithium data */ - -typedef struct lithium { - void * page0; /* virtual addresses */ - void * page1; - void * page2; - spinlock_t lock; /* protects codec and UST/MSC access */ -} lithium_t; - -/* - * li_destroy destroys the lithium_t structure and vm mappings. - */ - -static void li_destroy(lithium_t *lith) -{ - if (lith->page0) { - iounmap(lith->page0); - lith->page0 = NULL; - } - if (lith->page1) { - iounmap(lith->page1); - lith->page1 = NULL; - } - if (lith->page2) { - iounmap(lith->page2); - lith->page2 = NULL; - } -} - -/* - * li_create initializes the lithium_t structure and sets up vm mappings - * to access the registers. - * Returns 0 on success, -errno on failure. - */ - -static int __init li_create(lithium_t *lith, unsigned long baseaddr) -{ - spin_lock_init(&lith->lock); - lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE); - lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE); - lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE); - if (!lith->page0 || !lith->page1 || !lith->page2) { - li_destroy(lith); - return -ENOMEM; - } - return 0; -} - -/* - * basic register accessors - read/write long/byte - */ - -static __inline__ unsigned long li_readl(lithium_t *lith, int off) -{ - return * (volatile unsigned long *) (lith->page0 + off); -} - -static __inline__ unsigned char li_readb(lithium_t *lith, int off) -{ - return * (volatile unsigned char *) (lith->page0 + off); -} - -static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val) -{ - * (volatile unsigned long *) (lith->page0 + off) = val; -} - -static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val) -{ - * (volatile unsigned char *) (lith->page0 + off) = val; -} - -/*****************************************************************************/ -/* High Level Lithium Access */ - -/* - * Lithium DMA Notes - * - * Lithium has two dedicated DMA channels for audio. They are known - * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for - * input, and comm2 is for output. Each is controlled by three - * registers: BASE (base address), CFG (config) and CCTL - * (config/control). - * - * Each DMA channel points to a physically contiguous ring buffer in - * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.) - * There are three pointers into the ring buffer: read, write, and - * trigger. The pointers are 8 bits each. Each pointer points to - * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time, - * so there is no finer-granularity control. - * - * In comm1, the hardware updates the write ptr, and software updates - * the read ptr. In comm2, it's the opposite: hardware updates the - * read ptr, and software updates the write ptr. I designate the - * hardware-updated ptr as the hwptr, and the software-updated ptr as - * the swptr. - * - * The trigger ptr and trigger mask are used to trigger interrupts. - * From the Lithium spec, section 5.6.8, revision of 12/15/1998: - * - * Trigger Mask Value - * - * A three bit wide field that represents a power of two mask - * that is used whenever the trigger pointer is compared to its - * respective read or write pointer. A value of zero here - * implies a mask of 0xFF and a value of seven implies a mask - * 0x01. This value can be used to sub-divide the ring buffer - * into pie sections so that interrupts monitor the progress of - * hardware from section to section. - * - * My interpretation of that is, whenever the hw ptr is updated, it is - * compared with the trigger ptr, and the result is masked by the - * trigger mask. (Actually, by the complement of the trigger mask.) - * If the result is zero, an interrupt is triggered. I.e., interrupt - * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from - * the trigger register value as mask = (1 << (8 - tmreg)) - 1. - * - * In yet different words, setting tmreg to 0 causes an interrupt after - * every 256 DMA chunks (8192 bytes) or once per traversal of the - * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks - * (64 bytes) or 128 times per traversal of the ring buffer. - */ - -/* Lithium register offsets and bit definitions */ - -#define LI_HOST_CONTROLLER 0x000 -# define LI_HC_RESET 0x00008000 -# define LI_HC_LINK_ENABLE 0x00004000 -# define LI_HC_LINK_FAILURE 0x00000004 -# define LI_HC_LINK_CODEC 0x00000002 -# define LI_HC_LINK_READY 0x00000001 - -#define LI_INTR_STATUS 0x010 -#define LI_INTR_MASK 0x014 -# define LI_INTR_LINK_ERR 0x00008000 -# define LI_INTR_COMM2_TRIG 0x00000008 -# define LI_INTR_COMM2_UNDERFLOW 0x00000004 -# define LI_INTR_COMM1_TRIG 0x00000002 -# define LI_INTR_COMM1_OVERFLOW 0x00000001 - -#define LI_CODEC_COMMAND 0x018 -# define LI_CC_BUSY 0x00008000 -# define LI_CC_DIR 0x00000080 -# define LI_CC_DIR_RD LI_CC_DIR -# define LI_CC_DIR_WR (!LI_CC_DIR) -# define LI_CC_ADDR_MASK 0x0000007F - -#define LI_CODEC_DATA 0x01C - -#define LI_COMM1_BASE 0x100 -#define LI_COMM1_CTL 0x104 -# define LI_CCTL_RESET 0x80000000 -# define LI_CCTL_SIZE 0x70000000 -# define LI_CCTL_DMA_ENABLE 0x08000000 -# define LI_CCTL_TMASK 0x07000000 /* trigger mask */ -# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */ -# define LI_CCTL_RPTR 0x0000FF00 -# define LI_CCTL_WPTR 0x000000FF -#define LI_COMM1_CFG 0x108 -# define LI_CCFG_LOCK 0x00008000 -# define LI_CCFG_SLOT 0x00000070 -# define LI_CCFG_DIRECTION 0x00000008 -# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION) -# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION -# define LI_CCFG_MODE 0x00000004 -# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE) -# define LI_CCFG_MODE_STEREO LI_CCFG_MODE -# define LI_CCFG_FORMAT 0x00000003 -# define LI_CCFG_FMT_8BIT 0x00000000 -# define LI_CCFG_FMT_16BIT 0x00000001 -#define LI_COMM2_BASE 0x10C -#define LI_COMM2_CTL 0x110 - /* bit definitions are the same as LI_COMM1_CTL */ -#define LI_COMM2_CFG 0x114 - /* bit definitions are the same as LI_COMM1_CFG */ - -#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */ -#define LI_UST_HIGH 0x204 /* microseconds since boot */ - -#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */ -#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */ -#define LI_AUDIO2_UST 0x308 /* counts samples actually */ -#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */ - -/* - * Lithium's DMA engine operates on chunks of 32 bytes. We call that - * a DMACHUNK. - */ - -#define DMACHUNK_SHIFT 5 -#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT) -#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT) -#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT) - -/* - * Two convenient macros to shift bitfields into/out of position. - * - * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)). - * As long as mask is constant, we trust the compiler will change the - * multiply and divide into shifts. - */ - -#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask)) -#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask))) - -/* - * dma_chan_desc is invariant information about a Lithium - * DMA channel. There are two instances, li_comm1 and li_comm2. - * - * Note that the CCTL register fields are write ptr and read ptr, but what - * we care about are which pointer is updated by software and which by - * hardware. - */ - -typedef struct dma_chan_desc { - int basereg; - int cfgreg; - int ctlreg; - int hwptrreg; - int swptrreg; - int ustreg; - int mscreg; - unsigned long swptrmask; - int ad1843_slot; - int direction; /* LI_CCTL_DIR_IN/OUT */ -} dma_chan_desc_t; - -static const dma_chan_desc_t li_comm1 = { - LI_COMM1_BASE, /* base register offset */ - LI_COMM1_CFG, /* config register offset */ - LI_COMM1_CTL, /* control register offset */ - LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */ - LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */ - LI_AUDIO1_UST, /* ust reg offset */ - LI_AUDIO1_MSC, /* msc reg offset */ - LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */ - 2, /* ad1843 serial slot */ - LI_CCFG_DIR_IN /* direction */ -}; - -static const dma_chan_desc_t li_comm2 = { - LI_COMM2_BASE, /* base register offset */ - LI_COMM2_CFG, /* config register offset */ - LI_COMM2_CTL, /* control register offset */ - LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */ - LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */ - LI_AUDIO2_UST, /* ust reg offset */ - LI_AUDIO2_MSC, /* msc reg offset */ - LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */ - 2, /* ad1843 serial slot */ - LI_CCFG_DIR_OUT /* direction */ -}; - -/* - * dma_chan is variable information about a Lithium DMA channel. - * - * The desc field points to invariant information. - * The lith field points to a lithium_t which is passed - * to li_read* and li_write* to access the registers. - * The *val fields shadow the lithium registers' contents. - */ - -typedef struct dma_chan { - const dma_chan_desc_t *desc; - lithium_t *lith; - unsigned long baseval; - unsigned long cfgval; - unsigned long ctlval; -} dma_chan_t; - -/* - * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter). - * UST is time in microseconds since the system booted, and MSC is a - * counter that increments with every audio sample. - */ - -typedef struct ustmsc { - unsigned long long ust; - unsigned long msc; -} ustmsc_t; - -/* - * li_ad1843_wait waits until lithium says the AD1843 register - * exchange is not busy. Returns 0 on success, -EBUSY on timeout. - * - * Locking: must be called with lithium_lock held. - */ - -static int li_ad1843_wait(lithium_t *lith) -{ - unsigned long later = jiffies + 2; - while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY) - if (time_after_eq(jiffies, later)) - return -EBUSY; - return 0; -} - -/* - * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register. - * - * Returns unsigned register value on success, -errno on failure. - */ - -static int li_read_ad1843_reg(lithium_t *lith, int reg) -{ - int val; - - ASSERT(!in_interrupt()); - spin_lock(&lith->lock); - { - val = li_ad1843_wait(lith); - if (val == 0) { - li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg); - val = li_ad1843_wait(lith); - } - if (val == 0) - val = li_readl(lith, LI_CODEC_DATA); - } - spin_unlock(&lith->lock); - - DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n", - lith, reg, val); - - return val; -} - -/* - * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register. - */ - -static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval) -{ - spin_lock(&lith->lock); - { - if (li_ad1843_wait(lith) == 0) { - li_writel(lith, LI_CODEC_DATA, newval); - li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg); - } - } - spin_unlock(&lith->lock); -} - -/* - * li_setup_dma calculates all the register settings for DMA in a particular - * mode. It takes too many arguments. - */ - -static void li_setup_dma(dma_chan_t *chan, - const dma_chan_desc_t *desc, - lithium_t *lith, - unsigned long buffer_paddr, - int bufshift, - int fragshift, - int channels, - int sampsize) -{ - unsigned long mode, format; - unsigned long size, tmask; - - DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, " - "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n", - chan, desc, lith, buffer_paddr, - bufshift, fragshift, channels, sampsize); - - /* Reset the channel first. */ - - li_writel(lith, desc->ctlreg, LI_CCTL_RESET); - - ASSERT(channels == 1 || channels == 2); - if (channels == 2) - mode = LI_CCFG_MODE_STEREO; - else - mode = LI_CCFG_MODE_MONO; - ASSERT(sampsize == 1 || sampsize == 2); - if (sampsize == 2) - format = LI_CCFG_FMT_16BIT; - else - format = LI_CCFG_FMT_8BIT; - chan->desc = desc; - chan->lith = lith; - - /* - * Lithium DMA address register takes a 40-bit physical - * address, right-shifted by 8 so it fits in 32 bits. Bit 37 - * must be set -- it enables cache coherence. - */ - - ASSERT(!(buffer_paddr & 0xFF)); - chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8); - - chan->cfgval = ((chan->cfgval & ~LI_CCFG_LOCK) | - SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) | - desc->direction | - mode | - format); - - size = bufshift - 6; - tmask = 13 - fragshift; /* See Lithium DMA Notes above. */ - ASSERT(size >= 2 && size <= 7); - ASSERT(tmask >= 1 && tmask <= 7); - chan->ctlval = ((chan->ctlval & ~LI_CCTL_RESET) | - SHIFT_FIELD(size, LI_CCTL_SIZE) | - (chan->ctlval & ~LI_CCTL_DMA_ENABLE) | - SHIFT_FIELD(tmask, LI_CCTL_TMASK) | - SHIFT_FIELD(0, LI_CCTL_TPTR)); - - DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval); - DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval); - DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval); - - li_writel(lith, desc->basereg, chan->baseval); - li_writel(lith, desc->cfgreg, chan->cfgval); - li_writel(lith, desc->ctlreg, chan->ctlval); - - DBGRV(); -} - -static void li_shutdown_dma(dma_chan_t *chan) -{ - lithium_t *lith = chan->lith; - void * lith1 = lith->page1; - - DBGEV("(chan=0x%p)\n", chan); - - chan->ctlval &= ~LI_CCTL_DMA_ENABLE; - DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); - li_writel(lith, chan->desc->ctlreg, chan->ctlval); - - /* - * Offset 0x500 on Lithium page 1 is an undocumented, - * unsupported register that holds the zero sample value. - * Lithium is supposed to output zero samples when DMA is - * inactive, and repeat the last sample when DMA underflows. - * But it has a bug, where, after underflow occurs, the zero - * sample is not reset. - * - * I expect this to break in a future rev of Lithium. - */ - - if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT) - * (volatile unsigned long *) (lith1 + 0x500) = 0; -} - -/* - * li_activate_dma always starts dma at the beginning of the buffer. - * - * N.B., these may be called from interrupt. - */ - -static __inline__ void li_activate_dma(dma_chan_t *chan) -{ - chan->ctlval |= LI_CCTL_DMA_ENABLE; - DBGPV("ctlval = 0x%lx\n", chan->ctlval); - li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval); -} - -static void li_deactivate_dma(dma_chan_t *chan) -{ - lithium_t *lith = chan->lith; - void * lith2 = lith->page2; - - chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR); - DBGPV("ctlval = 0x%lx\n", chan->ctlval); - DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval); - li_writel(lith, chan->desc->ctlreg, chan->ctlval); - - /* - * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented, - * unsupported registers that are internal copies of the DMA - * read and write pointers. Because of a Lithium bug, these - * registers aren't zeroed correctly when DMA is shut off. So - * we whack them directly. - * - * I expect this to break in a future rev of Lithium. - */ - - if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) { - * (volatile unsigned long *) (lith2 + 0x98) = 0; - * (volatile unsigned long *) (lith2 + 0x9C) = 0; - } -} - -/* - * read/write the ring buffer pointers. These routines' arguments and results - * are byte offsets from the beginning of the ring buffer. - */ - -static __inline__ int li_read_swptr(dma_chan_t *chan) -{ - const unsigned long mask = chan->desc->swptrmask; - - return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask)); -} - -static __inline__ int li_read_hwptr(dma_chan_t *chan) -{ - return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg)); -} - -static __inline__ void li_write_swptr(dma_chan_t *chan, int val) -{ - const unsigned long mask = chan->desc->swptrmask; - - ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF))); - val = BYTES_TO_CHUNKS(val); - chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask); - li_writeb(chan->lith, chan->desc->swptrreg, val); -} - -/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */ - -static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc) -{ - lithium_t *lith = chan->lith; - const dma_chan_desc_t *desc = chan->desc; - unsigned long now_low, now_high0, now_high1, chan_ust; - - spin_lock(&lith->lock); - { - /* - * retry until we do all five reads without the - * high word changing. (High word increments - * every 2^32 microseconds, i.e., not often) - */ - do { - now_high0 = li_readl(lith, LI_UST_HIGH); - now_low = li_readl(lith, LI_UST_LOW); - - /* - * Lithium guarantees these two reads will be - * atomic -- ust will not increment after msc - * is read. - */ - - ustmsc->msc = li_readl(lith, desc->mscreg); - chan_ust = li_readl(lith, desc->ustreg); - - now_high1 = li_readl(lith, LI_UST_HIGH); - } while (now_high0 != now_high1); - } - spin_unlock(&lith->lock); - ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust); -} - -static void li_enable_interrupts(lithium_t *lith, unsigned int mask) -{ - DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); - - /* clear any already-pending interrupts. */ - - li_writel(lith, LI_INTR_STATUS, mask); - - /* enable the interrupts. */ - - mask |= li_readl(lith, LI_INTR_MASK); - li_writel(lith, LI_INTR_MASK, mask); -} - -static void li_disable_interrupts(lithium_t *lith, unsigned int mask) -{ - unsigned int keepmask; - - DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask); - - /* disable the interrupts */ - - keepmask = li_readl(lith, LI_INTR_MASK) & ~mask; - li_writel(lith, LI_INTR_MASK, keepmask); - - /* clear any pending interrupts. */ - - li_writel(lith, LI_INTR_STATUS, mask); -} - -/* Get the interrupt status and clear all pending interrupts. */ - -static unsigned int li_get_clear_intr_status(lithium_t *lith) -{ - unsigned int status; - - status = li_readl(lith, LI_INTR_STATUS); - li_writel(lith, LI_INTR_STATUS, ~0); - return status & li_readl(lith, LI_INTR_MASK); -} - -static int li_init(lithium_t *lith) -{ - /* 1. System power supplies stabilize. */ - - /* 2. Assert the ~RESET signal. */ - - li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET); - udelay(1); - - /* 3. Deassert the ~RESET signal and enter a wait period to allow - the AD1843 internal clocks and the external crystal oscillator - to stabilize. */ - - li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); - udelay(1); - - return 0; -} - -/*****************************************************************************/ -/* AD1843 access */ - -/* - * AD1843 bitfield definitions. All are named as in the AD1843 data - * sheet, with ad1843_ prepended and individual bit numbers removed. - * - * E.g., bits LSS0 through LSS2 become ad1843_LSS. - * - * Only the bitfields we need are defined. - */ - -typedef struct ad1843_bitfield { - char reg; - char lo_bit; - char nbits; -} ad1843_bitfield_t; - -static const ad1843_bitfield_t - ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ - ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ - ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ - ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ - ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ - ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ - ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ - ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ - ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ - ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ - ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ - ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ - ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ - ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ - ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ - ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ - ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ - ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ - ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ - ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ - ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ - ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ - ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ - ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ - ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ - ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ - ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ - ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ - ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ - ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ - ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ - ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ - ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */ - ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ - ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ - ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ - ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ - ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ - ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ - ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ - ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ - ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ - ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ - ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ - ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ - ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ - ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ - ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ - ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ - ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ - ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ - -/* - * The various registers of the AD1843 use three different formats for - * specifying gain. The ad1843_gain structure parameterizes the - * formats. - */ - -typedef struct ad1843_gain { - - int negative; /* nonzero if gain is negative. */ - const ad1843_bitfield_t *lfield; - const ad1843_bitfield_t *rfield; - -} ad1843_gain_t; - -static const ad1843_gain_t ad1843_gain_RECLEV - = { 0, &ad1843_LIG, &ad1843_RIG }; -static const ad1843_gain_t ad1843_gain_LINE - = { 1, &ad1843_LX1M, &ad1843_RX1M }; -static const ad1843_gain_t ad1843_gain_CD - = { 1, &ad1843_LX2M, &ad1843_RX2M }; -static const ad1843_gain_t ad1843_gain_MIC - = { 1, &ad1843_LMCM, &ad1843_RMCM }; -static const ad1843_gain_t ad1843_gain_PCM - = { 1, &ad1843_LDA1G, &ad1843_RDA1G }; - -/* read the current value of an AD1843 bitfield. */ - -static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field) -{ - int w = li_read_ad1843_reg(lith, field->reg); - int val = w >> field->lo_bit & ((1 << field->nbits) - 1); - - DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n", - lith, field->reg, field->lo_bit, field->nbits, val); - - return val; -} - -/* - * write a new value to an AD1843 bitfield and return the old value. - */ - -static int ad1843_write_bits(lithium_t *lith, - const ad1843_bitfield_t *field, - int newval) -{ - int w = li_read_ad1843_reg(lith, field->reg); - int mask = ((1 << field->nbits) - 1) << field->lo_bit; - int oldval = (w & mask) >> field->lo_bit; - int newbits = (newval << field->lo_bit) & mask; - w = (w & ~mask) | newbits; - (void) li_write_ad1843_reg(lith, field->reg, w); - - DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) " - "returns 0x%x\n", - lith, field->reg, field->lo_bit, field->nbits, newval, - oldval); - - return oldval; -} - -/* - * ad1843_read_multi reads multiple bitfields from the same AD1843 - * register. It uses a single read cycle to do it. (Reading the - * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 - * microseconds.) - * - * Called ike this. - * - * ad1843_read_multi(lith, nfields, - * &ad1843_FIELD1, &val1, - * &ad1843_FIELD2, &val2, ...); - */ - -static void ad1843_read_multi(lithium_t *lith, int argcount, ...) -{ - va_list ap; - const ad1843_bitfield_t *fp; - int w = 0, mask, *value, reg = -1; - - va_start(ap, argcount); - while (--argcount >= 0) { - fp = va_arg(ap, const ad1843_bitfield_t *); - value = va_arg(ap, int *); - if (reg == -1) { - reg = fp->reg; - w = li_read_ad1843_reg(lith, reg); - } - ASSERT(reg == fp->reg); - mask = (1 << fp->nbits) - 1; - *value = w >> fp->lo_bit & mask; - } - va_end(ap); -} - -/* - * ad1843_write_multi stores multiple bitfields into the same AD1843 - * register. It uses one read and one write cycle to do it. - * - * Called like this. - * - * ad1843_write_multi(lith, nfields, - * &ad1843_FIELD1, val1, - * &ad1843_FIELF2, val2, ...); - */ - -static void ad1843_write_multi(lithium_t *lith, int argcount, ...) -{ - va_list ap; - int reg; - const ad1843_bitfield_t *fp; - int value; - int w, m, mask, bits; - - mask = 0; - bits = 0; - reg = -1; - - va_start(ap, argcount); - while (--argcount >= 0) { - fp = va_arg(ap, const ad1843_bitfield_t *); - value = va_arg(ap, int); - if (reg == -1) - reg = fp->reg; - ASSERT(fp->reg == reg); - m = ((1 << fp->nbits) - 1) << fp->lo_bit; - mask |= m; - bits |= (value << fp->lo_bit) & m; - } - va_end(ap); - ASSERT(!(bits & ~mask)); - if (~mask & 0xFFFF) - w = li_read_ad1843_reg(lith, reg); - else - w = 0; - w = (w & ~mask) | bits; - (void) li_write_ad1843_reg(lith, reg, w); -} - -/* - * ad1843_get_gain reads the specified register and extracts the gain value - * using the supplied gain type. It returns the gain in OSS format. - */ - -static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp) -{ - int lg, rg; - unsigned short mask = (1 << gp->lfield->nbits) - 1; - - ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg); - if (gp->negative) { - lg = mask - lg; - rg = mask - rg; - } - lg = (lg * 100 + (mask >> 1)) / mask; - rg = (rg * 100 + (mask >> 1)) / mask; - return lg << 0 | rg << 8; -} - -/* - * Set an audio channel's gain. Converts from OSS format to AD1843's - * format. - * - * Returns the new gain, which may be lower than the old gain. - */ - -static int ad1843_set_gain(lithium_t *lith, - const ad1843_gain_t *gp, - int newval) -{ - unsigned short mask = (1 << gp->lfield->nbits) - 1; - - int lg = newval >> 0 & 0xFF; - int rg = newval >> 8; - if (lg < 0 || lg > 100 || rg < 0 || rg > 100) - return -EINVAL; - lg = (lg * mask + (mask >> 1)) / 100; - rg = (rg * mask + (mask >> 1)) / 100; - if (gp->negative) { - lg = mask - lg; - rg = mask - rg; - } - ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg); - return ad1843_get_gain(lith, gp); -} - -/* Returns the current recording source, in OSS format. */ - -static int ad1843_get_recsrc(lithium_t *lith) -{ - int ls = ad1843_read_bits(lith, &ad1843_LSS); - - switch (ls) { - case 1: - return SOUND_MASK_MIC; - case 2: - return SOUND_MASK_LINE; - case 3: - return SOUND_MASK_CD; - case 6: - return SOUND_MASK_PCM; - default: - ASSERT(0); - return -1; - } -} - -/* - * Enable/disable digital resample mode in the AD1843. - * - * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down - * while switching modes. So we save DA1's state (DA2's state is not - * interesting), power them down, switch into/out of resample mode, - * power them up, and restore state. - * - * This will cause audible glitches if D/A or A/D is going on, so the - * driver disallows that (in mixer_write_ioctl()). - * - * The open question is, is this worth doing? I'm leaving it in, - * because it's written, but... - */ - -static void ad1843_set_resample_mode(lithium_t *lith, int onoff) -{ - /* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */ - int save_da1 = li_read_ad1843_reg(lith, 9); - - /* Power down A/D and D/A. */ - ad1843_write_multi(lith, 4, - &ad1843_DA1EN, 0, - &ad1843_DA2EN, 0, - &ad1843_ADLEN, 0, - &ad1843_ADREN, 0); - - /* Switch mode */ - ASSERT(onoff == 0 || onoff == 1); - ad1843_write_bits(lith, &ad1843_DRSFLT, onoff); - - /* Power up A/D and D/A. */ - ad1843_write_multi(lith, 3, - &ad1843_DA1EN, 1, - &ad1843_ADLEN, 1, - &ad1843_ADREN, 1); - - /* Restore DA1 mute and gain. */ - li_write_ad1843_reg(lith, 9, save_da1); -} - -/* - * Set recording source. Arg newsrc specifies an OSS channel mask. - * - * The complication is that when we switch into/out of loopback mode - * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of - * digital resampling mode. - * - * Returns newsrc on success, -errno on failure. - */ - -static int ad1843_set_recsrc(lithium_t *lith, int newsrc) -{ - int bits; - int oldbits; - - switch (newsrc) { - case SOUND_MASK_PCM: - bits = 6; - break; - - case SOUND_MASK_MIC: - bits = 1; - break; - - case SOUND_MASK_LINE: - bits = 2; - break; - - case SOUND_MASK_CD: - bits = 3; - break; - - default: - return -EINVAL; - } - oldbits = ad1843_read_bits(lith, &ad1843_LSS); - if (newsrc == SOUND_MASK_PCM && oldbits != 6) { - DBGP("enabling digital resample mode\n"); - ad1843_set_resample_mode(lith, 1); - ad1843_write_multi(lith, 2, - &ad1843_DAADL, 2, - &ad1843_DAADR, 2); - } else if (newsrc != SOUND_MASK_PCM && oldbits == 6) { - DBGP("disabling digital resample mode\n"); - ad1843_set_resample_mode(lith, 0); - ad1843_write_multi(lith, 2, - &ad1843_DAADL, 0, - &ad1843_DAADR, 0); - } - ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits); - return newsrc; -} - -/* - * Return current output sources, in OSS format. - */ - -static int ad1843_get_outsrc(lithium_t *lith) -{ - int pcm, line, mic, cd; - - pcm = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM; - line = ad1843_read_bits(lith, &ad1843_LX1MM) ? 0 : SOUND_MASK_LINE; - cd = ad1843_read_bits(lith, &ad1843_LX2MM) ? 0 : SOUND_MASK_CD; - mic = ad1843_read_bits(lith, &ad1843_LMCMM) ? 0 : SOUND_MASK_MIC; - - return pcm | line | cd | mic; -} - -/* - * Set output sources. Arg is a mask of active sources in OSS format. - * - * Returns source mask on success, -errno on failure. - */ - -static int ad1843_set_outsrc(lithium_t *lith, int mask) -{ - int pcm, line, mic, cd; - - if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_CD | SOUND_MASK_MIC)) - return -EINVAL; - pcm = (mask & SOUND_MASK_PCM) ? 0 : 1; - line = (mask & SOUND_MASK_LINE) ? 0 : 1; - mic = (mask & SOUND_MASK_MIC) ? 0 : 1; - cd = (mask & SOUND_MASK_CD) ? 0 : 1; - - ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm); - ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line); - ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd, &ad1843_RX2MM, cd); - ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic, &ad1843_RMCMM, mic); - - return mask; -} - -/* Setup ad1843 for D/A conversion. */ - -static void ad1843_setup_dac(lithium_t *lith, - int framerate, - int fmt, - int channels) -{ - int ad_fmt = 0, ad_mode = 0; - - DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", - lith, framerate, fmt, channels); - - switch (fmt) { - case AFMT_S8: ad_fmt = 1; break; - case AFMT_U8: ad_fmt = 1; break; - case AFMT_S16_LE: ad_fmt = 1; break; - case AFMT_MU_LAW: ad_fmt = 2; break; - case AFMT_A_LAW: ad_fmt = 3; break; - default: ASSERT(0); - } - - switch (channels) { - case 2: ad_mode = 0; break; - case 1: ad_mode = 1; break; - default: ASSERT(0); - } - - DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt); - ASSERT(framerate >= 4000 && framerate <= 49000); - ad1843_write_bits(lith, &ad1843_C1C, framerate); - ad1843_write_multi(lith, 2, - &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt); -} - -static void ad1843_shutdown_dac(lithium_t *lith) -{ - ad1843_write_bits(lith, &ad1843_DA1F, 1); -} - -static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels) -{ - int da_fmt = 0; - - DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n", - lith, framerate, fmt, channels); - - switch (fmt) { - case AFMT_S8: da_fmt = 1; break; - case AFMT_U8: da_fmt = 1; break; - case AFMT_S16_LE: da_fmt = 1; break; - case AFMT_MU_LAW: da_fmt = 2; break; - case AFMT_A_LAW: da_fmt = 3; break; - default: ASSERT(0); - } - - DBGPV("da_fmt = %d\n", da_fmt); - ASSERT(framerate >= 4000 && framerate <= 49000); - ad1843_write_bits(lith, &ad1843_C2C, framerate); - ad1843_write_multi(lith, 2, - &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); -} - -static void ad1843_shutdown_adc(lithium_t *lith) -{ - /* nothing to do */ -} - -/* - * Fully initialize the ad1843. As described in the AD1843 data - * sheet, section "START-UP SEQUENCE". The numbered comments are - * subsection headings from the data sheet. See the data sheet, pages - * 52-54, for more info. - * - * return 0 on success, -errno on failure. */ - -static int __init ad1843_init(lithium_t *lith) -{ - unsigned long later; - int err; - - err = li_init(lith); - if (err) - return err; - - if (ad1843_read_bits(lith, &ad1843_INIT) != 0) { - printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n"); - return -EIO; - } - - ad1843_write_bits(lith, &ad1843_SCF, 1); - - /* 4. Put the conversion resources into standby. */ - - ad1843_write_bits(lith, &ad1843_PDNI, 0); - later = jiffies + HZ / 2; /* roughly half a second */ - DBGDO(shut_up++); - while (ad1843_read_bits(lith, &ad1843_PDNO)) { - if (time_after(jiffies, later)) { - printk(KERN_ERR - "vwsnd audio: AD1843 won't power up\n"); - return -EIO; - } - schedule(); - } - DBGDO(shut_up--); - - /* 5. Power up the clock generators and enable clock output pins. */ - - ad1843_write_multi(lith, 2, &ad1843_C1EN, 1, &ad1843_C2EN, 1); - - /* 6. Configure conversion resources while they are in standby. */ - - /* DAC1 uses clock 1 as source, ADC uses clock 2. Always. */ - - ad1843_write_multi(lith, 3, - &ad1843_DA1C, 1, - &ad1843_ADLC, 2, - &ad1843_ADRC, 2); - - /* 7. Enable conversion resources. */ - - ad1843_write_bits(lith, &ad1843_ADTLK, 1); - ad1843_write_multi(lith, 5, - &ad1843_ANAEN, 1, - &ad1843_AAMEN, 1, - &ad1843_DA1EN, 1, - &ad1843_ADLEN, 1, - &ad1843_ADREN, 1); - - /* 8. Configure conversion resources while they are enabled. */ - - ad1843_write_bits(lith, &ad1843_DA1C, 1); - - /* Unmute all channels. */ - - ad1843_set_outsrc(lith, - (SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_MIC | SOUND_MASK_CD)); - ad1843_write_multi(lith, 2, &ad1843_LDA1AM, 0, &ad1843_RDA1AM, 0); - - /* Set default recording source to Line In and set - * mic gain to +20 dB. - */ - - ad1843_set_recsrc(lith, SOUND_MASK_LINE); - ad1843_write_multi(lith, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); - - /* Set Speaker Out level to +/- 4V and unmute it. */ - - ad1843_write_multi(lith, 2, &ad1843_HPOS, 1, &ad1843_HPOM, 0); - - return 0; -} - -/*****************************************************************************/ -/* PCM I/O */ - -#define READ_INTR_MASK (LI_INTR_COMM1_TRIG | LI_INTR_COMM1_OVERFLOW) -#define WRITE_INTR_MASK (LI_INTR_COMM2_TRIG | LI_INTR_COMM2_UNDERFLOW) - -typedef enum vwsnd_port_swstate { /* software state */ - SW_OFF, - SW_INITIAL, - SW_RUN, - SW_DRAIN, -} vwsnd_port_swstate_t; - -typedef enum vwsnd_port_hwstate { /* hardware state */ - HW_STOPPED, - HW_RUNNING, -} vwsnd_port_hwstate_t; - -/* - * These flags are read by ISR, but only written at baseline. - */ - -typedef enum vwsnd_port_flags { - DISABLED = 1 << 0, - ERFLOWN = 1 << 1, /* overflown or underflown */ - HW_BUSY = 1 << 2, -} vwsnd_port_flags_t; - -/* - * vwsnd_port is the per-port data structure. Each device has two - * ports, one for input and one for output. - * - * Locking: - * - * port->lock protects: hwstate, flags, swb_[iu]_avail. - * - * devc->io_mutex protects: swstate, sw_*, swb_[iu]_idx. - * - * everything else is only written by open/release or - * pcm_{setup,shutdown}(), which are serialized by a - * combination of devc->open_mutex and devc->io_mutex. - */ - -typedef struct vwsnd_port { - - spinlock_t lock; - wait_queue_head_t queue; - vwsnd_port_swstate_t swstate; - vwsnd_port_hwstate_t hwstate; - vwsnd_port_flags_t flags; - - int sw_channels; - int sw_samplefmt; - int sw_framerate; - int sample_size; - int frame_size; - unsigned int zero_word; /* zero for the sample format */ - - int sw_fragshift; - int sw_fragcount; - int sw_subdivshift; - - unsigned int hw_fragshift; - unsigned int hw_fragsize; - unsigned int hw_fragcount; - - int hwbuf_size; - unsigned long hwbuf_paddr; - unsigned long hwbuf_vaddr; - void * hwbuf; /* hwbuf == hwbuf_vaddr */ - int hwbuf_max; /* max bytes to preload */ - - void * swbuf; - unsigned int swbuf_size; /* size in bytes */ - unsigned int swb_u_idx; /* index of next user byte */ - unsigned int swb_i_idx; /* index of next intr byte */ - unsigned int swb_u_avail; /* # bytes avail to user */ - unsigned int swb_i_avail; /* # bytes avail to intr */ - - dma_chan_t chan; - - /* Accounting */ - - int byte_count; - int frag_count; - int MSC_offset; - -} vwsnd_port_t; - -/* vwsnd_dev is the per-device data structure. */ - -typedef struct vwsnd_dev { - struct vwsnd_dev *next_dev; - int audio_minor; /* minor number of audio device */ - int mixer_minor; /* minor number of mixer device */ - - struct mutex open_mutex; - struct mutex io_mutex; - struct mutex mix_mutex; - fmode_t open_mode; - wait_queue_head_t open_wait; - - lithium_t lith; - - vwsnd_port_t rport; - vwsnd_port_t wport; -} vwsnd_dev_t; - -static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */ - -static atomic_t vwsnd_use_count = ATOMIC_INIT(0); - -# define INC_USE_COUNT (atomic_inc(&vwsnd_use_count)) -# define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count)) -# define IN_USE (atomic_read(&vwsnd_use_count) != 0) - -/* - * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may - * be up to 8 Kb. This driver always uses 8 Kb. - * - * Memory bug workaround -- I'm not sure what's going on here, but - * somehow pcm_copy_out() was triggering segv's going on to the next - * page of the hw buffer. So, I make the hw buffer one size bigger - * than we actually use. That way, the following page is allocated - * and mapped, and no error. I suspect that something is broken - * in Cobalt, but haven't really investigated. HBO is the actual - * size of the buffer, and HWBUF_ORDER is what we allocate. - */ - -#define HWBUF_SHIFT 13 -#define HWBUF_SIZE (1 << HWBUF_SHIFT) -# define HBO (HWBUF_SHIFT > PAGE_SHIFT ? HWBUF_SHIFT - PAGE_SHIFT : 0) -# define HWBUF_ORDER (HBO + 1) /* next size bigger */ -#define MIN_SPEED 4000 -#define MAX_SPEED 49000 - -#define MIN_FRAGSHIFT (DMACHUNK_SHIFT + 1) -#define MAX_FRAGSHIFT (PAGE_SHIFT) -#define MIN_FRAGSIZE (1 << MIN_FRAGSHIFT) -#define MAX_FRAGSIZE (1 << MAX_FRAGSHIFT) -#define MIN_FRAGCOUNT(fragsize) 3 -#define MAX_FRAGCOUNT(fragsize) (32 * PAGE_SIZE / (fragsize)) -#define DEFAULT_FRAGSHIFT 12 -#define DEFAULT_FRAGCOUNT 16 -#define DEFAULT_SUBDIVSHIFT 0 - -/* - * The software buffer (swbuf) is a ring buffer shared between user - * level and interrupt level. Each level owns some of the bytes in - * the buffer, and may give bytes away by calling swb_inc_{u,i}(). - * User level calls _u for user, and interrupt level calls _i for - * interrupt. - * - * port->swb_{u,i}_avail is the number of bytes available to that level. - * - * port->swb_{u,i}_idx is the index of the first available byte in the - * buffer. - * - * Each level calls swb_inc_{u,i}() to atomically increment its index, - * recalculate the number of bytes available for both sides, and - * return the number of bytes available. Since each side can only - * give away bytes, the other side can only increase the number of - * bytes available to this side. Each side updates its own index - * variable, swb_{u,i}_idx, so no lock is needed to read it. - * - * To query the number of bytes available, call swb_inc_{u,i} with an - * increment of zero. - */ - -static __inline__ unsigned int __swb_inc_u(vwsnd_port_t *port, int inc) -{ - if (inc) { - port->swb_u_idx += inc; - port->swb_u_idx %= port->swbuf_size; - port->swb_u_avail -= inc; - port->swb_i_avail += inc; - } - return port->swb_u_avail; -} - -static __inline__ unsigned int swb_inc_u(vwsnd_port_t *port, int inc) -{ - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&port->lock, flags); - { - ret = __swb_inc_u(port, inc); - } - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -static __inline__ unsigned int __swb_inc_i(vwsnd_port_t *port, int inc) -{ - if (inc) { - port->swb_i_idx += inc; - port->swb_i_idx %= port->swbuf_size; - port->swb_i_avail -= inc; - port->swb_u_avail += inc; - } - return port->swb_i_avail; -} - -static __inline__ unsigned int swb_inc_i(vwsnd_port_t *port, int inc) -{ - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&port->lock, flags); - { - ret = __swb_inc_i(port, inc); - } - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -/* - * pcm_setup - this routine initializes all port state after - * mode-setting ioctls have been done, but before the first I/O is - * done. - * - * Locking: called with devc->io_mutex held. - * - * Returns 0 on success, -errno on failure. - */ - -static int pcm_setup(vwsnd_dev_t *devc, - vwsnd_port_t *rport, - vwsnd_port_t *wport) -{ - vwsnd_port_t *aport = rport ? rport : wport; - int sample_size; - unsigned int zero_word; - - DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); - - ASSERT(aport != NULL); - if (aport->swbuf != NULL) - return 0; - switch (aport->sw_samplefmt) { - case AFMT_MU_LAW: - sample_size = 1; - zero_word = 0xFFFFFFFF ^ 0x80808080; - break; - - case AFMT_A_LAW: - sample_size = 1; - zero_word = 0xD5D5D5D5 ^ 0x80808080; - break; - - case AFMT_U8: - sample_size = 1; - zero_word = 0x80808080; - break; - - case AFMT_S8: - sample_size = 1; - zero_word = 0x00000000; - break; - - case AFMT_S16_LE: - sample_size = 2; - zero_word = 0x00000000; - break; - - default: - sample_size = 0; /* prevent compiler warning */ - zero_word = 0; - ASSERT(0); - } - aport->sample_size = sample_size; - aport->zero_word = zero_word; - aport->frame_size = aport->sw_channels * aport->sample_size; - aport->hw_fragshift = aport->sw_fragshift - aport->sw_subdivshift; - aport->hw_fragsize = 1 << aport->hw_fragshift; - aport->hw_fragcount = aport->sw_fragcount << aport->sw_subdivshift; - ASSERT(aport->hw_fragsize >= MIN_FRAGSIZE); - ASSERT(aport->hw_fragsize <= MAX_FRAGSIZE); - ASSERT(aport->hw_fragcount >= MIN_FRAGCOUNT(aport->hw_fragsize)); - ASSERT(aport->hw_fragcount <= MAX_FRAGCOUNT(aport->hw_fragsize)); - if (rport) { - int hwfrags, swfrags; - rport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE; - hwfrags = rport->hwbuf_max >> aport->hw_fragshift; - swfrags = aport->hw_fragcount - hwfrags; - if (swfrags < 2) - swfrags = 2; - rport->swbuf_size = swfrags * aport->hw_fragsize; - DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags); - DBGPV("read hwbuf_max = %d, swbuf_size = %d\n", - rport->hwbuf_max, rport->swbuf_size); - } - if (wport) { - int hwfrags, swfrags; - int total_bytes = aport->hw_fragcount * aport->hw_fragsize; - wport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE; - if (wport->hwbuf_max > total_bytes) - wport->hwbuf_max = total_bytes; - hwfrags = wport->hwbuf_max >> aport->hw_fragshift; - DBGPV("hwfrags = %d\n", hwfrags); - swfrags = aport->hw_fragcount - hwfrags; - if (swfrags < 2) - swfrags = 2; - wport->swbuf_size = swfrags * aport->hw_fragsize; - DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags); - DBGPV("write hwbuf_max = %d, swbuf_size = %d\n", - wport->hwbuf_max, wport->swbuf_size); - } - - aport->swb_u_idx = 0; - aport->swb_i_idx = 0; - aport->byte_count = 0; - - /* - * Is this a Cobalt bug? We need to make this buffer extend - * one page further than we actually use -- somehow memcpy - * causes an exceptoin otherwise. I suspect there's a bug in - * Cobalt (or somewhere) where it's generating a fault on a - * speculative load or something. Obviously, I haven't taken - * the time to track it down. - */ - - aport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); - if (!aport->swbuf) - return -ENOMEM; - if (rport && wport) { - ASSERT(aport == rport); - ASSERT(wport->swbuf == NULL); - /* One extra page - see comment above. */ - wport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE); - if (!wport->swbuf) { - vfree(aport->swbuf); - aport->swbuf = NULL; - return -ENOMEM; - } - wport->sample_size = rport->sample_size; - wport->zero_word = rport->zero_word; - wport->frame_size = rport->frame_size; - wport->hw_fragshift = rport->hw_fragshift; - wport->hw_fragsize = rport->hw_fragsize; - wport->hw_fragcount = rport->hw_fragcount; - wport->swbuf_size = rport->swbuf_size; - wport->hwbuf_max = rport->hwbuf_max; - wport->swb_u_idx = rport->swb_u_idx; - wport->swb_i_idx = rport->swb_i_idx; - wport->byte_count = rport->byte_count; - } - if (rport) { - rport->swb_u_avail = 0; - rport->swb_i_avail = rport->swbuf_size; - rport->swstate = SW_RUN; - li_setup_dma(&rport->chan, - &li_comm1, - &devc->lith, - rport->hwbuf_paddr, - HWBUF_SHIFT, - rport->hw_fragshift, - rport->sw_channels, - rport->sample_size); - ad1843_setup_adc(&devc->lith, - rport->sw_framerate, - rport->sw_samplefmt, - rport->sw_channels); - li_enable_interrupts(&devc->lith, READ_INTR_MASK); - if (!(rport->flags & DISABLED)) { - ustmsc_t ustmsc; - rport->hwstate = HW_RUNNING; - li_activate_dma(&rport->chan); - li_read_USTMSC(&rport->chan, &ustmsc); - rport->MSC_offset = ustmsc.msc; - } - } - if (wport) { - if (wport->hwbuf_max > wport->swbuf_size) - wport->hwbuf_max = wport->swbuf_size; - wport->flags &= ~ERFLOWN; - wport->swb_u_avail = wport->swbuf_size; - wport->swb_i_avail = 0; - wport->swstate = SW_RUN; - li_setup_dma(&wport->chan, - &li_comm2, - &devc->lith, - wport->hwbuf_paddr, - HWBUF_SHIFT, - wport->hw_fragshift, - wport->sw_channels, - wport->sample_size); - ad1843_setup_dac(&devc->lith, - wport->sw_framerate, - wport->sw_samplefmt, - wport->sw_channels); - li_enable_interrupts(&devc->lith, WRITE_INTR_MASK); - } - DBGRV(); - return 0; -} - -/* - * pcm_shutdown_port - shut down one port (direction) for PCM I/O. - * Only called from pcm_shutdown. - */ - -static void pcm_shutdown_port(vwsnd_dev_t *devc, - vwsnd_port_t *aport, - unsigned int mask) -{ - unsigned long flags; - vwsnd_port_hwstate_t hwstate; - DECLARE_WAITQUEUE(wait, current); - - aport->swstate = SW_INITIAL; - add_wait_queue(&aport->queue, &wait); - while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - spin_lock_irqsave(&aport->lock, flags); - { - hwstate = aport->hwstate; - } - spin_unlock_irqrestore(&aport->lock, flags); - if (hwstate == HW_STOPPED) - break; - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&aport->queue, &wait); - li_disable_interrupts(&devc->lith, mask); - if (aport == &devc->rport) - ad1843_shutdown_adc(&devc->lith); - else /* aport == &devc->wport) */ - ad1843_shutdown_dac(&devc->lith); - li_shutdown_dma(&aport->chan); - vfree(aport->swbuf); - aport->swbuf = NULL; - aport->byte_count = 0; -} - -/* - * pcm_shutdown undoes what pcm_setup did. - * Also sets the ports' swstate to newstate. - */ - -static void pcm_shutdown(vwsnd_dev_t *devc, - vwsnd_port_t *rport, - vwsnd_port_t *wport) -{ - DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport); - - if (rport && rport->swbuf) { - DBGPV("shutting down rport\n"); - pcm_shutdown_port(devc, rport, READ_INTR_MASK); - } - if (wport && wport->swbuf) { - DBGPV("shutting down wport\n"); - pcm_shutdown_port(devc, wport, WRITE_INTR_MASK); - } - DBGRV(); -} - -static void pcm_copy_in(vwsnd_port_t *rport, int swidx, int hwidx, int nb) -{ - char *src = rport->hwbuf + hwidx; - char *dst = rport->swbuf + swidx; - int fmt = rport->sw_samplefmt; - - DBGPV("swidx = %d, hwidx = %d\n", swidx, hwidx); - ASSERT(rport->hwbuf != NULL); - ASSERT(rport->swbuf != NULL); - ASSERT(nb > 0 && (nb % 32) == 0); - ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); - ASSERT(swidx >= 0 && swidx + nb <= rport->swbuf_size); - ASSERT(hwidx >= 0 && hwidx + nb <= rport->hwbuf_size); - - if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { - - /* See Sample Format Notes above. */ - - char *end = src + nb; - while (src < end) - *dst++ = *src++ ^ 0x80; - } else - memcpy(dst, src, nb); -} - -static void pcm_copy_out(vwsnd_port_t *wport, int swidx, int hwidx, int nb) -{ - char *src = wport->swbuf + swidx; - char *dst = wport->hwbuf + hwidx; - int fmt = wport->sw_samplefmt; - - ASSERT(nb > 0 && (nb % 32) == 0); - ASSERT(wport->hwbuf != NULL); - ASSERT(wport->swbuf != NULL); - ASSERT(swidx % 32 == 0 && hwidx % 32 == 0); - ASSERT(swidx >= 0 && swidx + nb <= wport->swbuf_size); - ASSERT(hwidx >= 0 && hwidx + nb <= wport->hwbuf_size); - if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) { - - /* See Sample Format Notes above. */ - - char *end = src + nb; - while (src < end) - *dst++ = *src++ ^ 0x80; - } else - memcpy(dst, src, nb); -} - -/* - * pcm_output() is called both from baselevel and from interrupt level. - * This is where audio frames are copied into the hardware-accessible - * ring buffer. - * - * Locking note: The part of this routine that figures out what to do - * holds wport->lock. The longer part releases wport->lock, but sets - * wport->flags & HW_BUSY. Afterward, it reacquires wport->lock, and - * checks for more work to do. - * - * If another thread calls pcm_output() while HW_BUSY is set, it - * returns immediately, knowing that the thread that set HW_BUSY will - * look for more work to do before returning. - * - * This has the advantage that port->lock is held for several short - * periods instead of one long period. Also, when pcm_output is - * called from base level, it reenables interrupts. - */ - -static void pcm_output(vwsnd_dev_t *devc, int erflown, int nb) -{ - vwsnd_port_t *wport = &devc->wport; - const int hwmax = wport->hwbuf_max; - const int hwsize = wport->hwbuf_size; - const int swsize = wport->swbuf_size; - const int fragsize = wport->hw_fragsize; - unsigned long iflags; - - DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); - spin_lock_irqsave(&wport->lock, iflags); - if (erflown) - wport->flags |= ERFLOWN; - (void) __swb_inc_u(wport, nb); - if (wport->flags & HW_BUSY) { - spin_unlock_irqrestore(&wport->lock, iflags); - DBGPV("returning: HW BUSY\n"); - return; - } - if (wport->flags & DISABLED) { - spin_unlock_irqrestore(&wport->lock, iflags); - DBGPV("returning: DISABLED\n"); - return; - } - wport->flags |= HW_BUSY; - while (1) { - int swptr, hwptr, hw_avail, sw_avail, swidx; - vwsnd_port_hwstate_t hwstate = wport->hwstate; - vwsnd_port_swstate_t swstate = wport->swstate; - int hw_unavail; - ustmsc_t ustmsc; - - hwptr = li_read_hwptr(&wport->chan); - swptr = li_read_swptr(&wport->chan); - hw_unavail = (swptr - hwptr + hwsize) % hwsize; - hw_avail = (hwmax - hw_unavail) & -fragsize; - sw_avail = wport->swb_i_avail & -fragsize; - if (sw_avail && swstate == SW_RUN) { - if (wport->flags & ERFLOWN) { - wport->flags &= ~ERFLOWN; - } - } else if (swstate == SW_INITIAL || - swstate == SW_OFF || - (swstate == SW_DRAIN && - !sw_avail && - (wport->flags & ERFLOWN))) { - DBGP("stopping. hwstate = %d\n", hwstate); - if (hwstate != HW_STOPPED) { - li_deactivate_dma(&wport->chan); - wport->hwstate = HW_STOPPED; - } - wake_up(&wport->queue); - break; - } - if (!sw_avail || !hw_avail) - break; - spin_unlock_irqrestore(&wport->lock, iflags); - - /* - * We gave up the port lock, but we have the HW_BUSY flag. - * Proceed without accessing any nonlocal state. - * Do not exit the loop -- must check for more work. - */ - - swidx = wport->swb_i_idx; - nb = hw_avail; - if (nb > sw_avail) - nb = sw_avail; - if (nb > hwsize - swptr) - nb = hwsize - swptr; /* don't overflow hwbuf */ - if (nb > swsize - swidx) - nb = swsize - swidx; /* don't overflow swbuf */ - ASSERT(nb > 0); - if (nb % fragsize) { - DBGP("nb = %d, fragsize = %d\n", nb, fragsize); - DBGP("hw_avail = %d\n", hw_avail); - DBGP("sw_avail = %d\n", sw_avail); - DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); - DBGP("swsize = %d, swidx = %d\n", swsize, swidx); - } - ASSERT(!(nb % fragsize)); - DBGPV("copying swb[%d..%d] to hwb[%d..%d]\n", - swidx, swidx + nb, swptr, swptr + nb); - pcm_copy_out(wport, swidx, swptr, nb); - li_write_swptr(&wport->chan, (swptr + nb) % hwsize); - spin_lock_irqsave(&wport->lock, iflags); - if (hwstate == HW_STOPPED) { - DBGPV("starting\n"); - li_activate_dma(&wport->chan); - wport->hwstate = HW_RUNNING; - li_read_USTMSC(&wport->chan, &ustmsc); - ASSERT(wport->byte_count % wport->frame_size == 0); - wport->MSC_offset = ustmsc.msc - wport->byte_count / wport->frame_size; - } - __swb_inc_i(wport, nb); - wport->byte_count += nb; - wport->frag_count += nb / fragsize; - ASSERT(nb % fragsize == 0); - wake_up(&wport->queue); - } - wport->flags &= ~HW_BUSY; - spin_unlock_irqrestore(&wport->lock, iflags); - DBGRV(); -} - -/* - * pcm_input() is called both from baselevel and from interrupt level. - * This is where audio frames are copied out of the hardware-accessible - * ring buffer. - * - * Locking note: The part of this routine that figures out what to do - * holds rport->lock. The longer part releases rport->lock, but sets - * rport->flags & HW_BUSY. Afterward, it reacquires rport->lock, and - * checks for more work to do. - * - * If another thread calls pcm_input() while HW_BUSY is set, it - * returns immediately, knowing that the thread that set HW_BUSY will - * look for more work to do before returning. - * - * This has the advantage that port->lock is held for several short - * periods instead of one long period. Also, when pcm_input is - * called from base level, it reenables interrupts. - */ - -static void pcm_input(vwsnd_dev_t *devc, int erflown, int nb) -{ - vwsnd_port_t *rport = &devc->rport; - const int hwmax = rport->hwbuf_max; - const int hwsize = rport->hwbuf_size; - const int swsize = rport->swbuf_size; - const int fragsize = rport->hw_fragsize; - unsigned long iflags; - - DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb); - - spin_lock_irqsave(&rport->lock, iflags); - if (erflown) - rport->flags |= ERFLOWN; - (void) __swb_inc_u(rport, nb); - if (rport->flags & HW_BUSY || !rport->swbuf) { - spin_unlock_irqrestore(&rport->lock, iflags); - DBGPV("returning: HW BUSY or !swbuf\n"); - return; - } - if (rport->flags & DISABLED) { - spin_unlock_irqrestore(&rport->lock, iflags); - DBGPV("returning: DISABLED\n"); - return; - } - rport->flags |= HW_BUSY; - while (1) { - int swptr, hwptr, hw_avail, sw_avail, swidx; - vwsnd_port_hwstate_t hwstate = rport->hwstate; - vwsnd_port_swstate_t swstate = rport->swstate; - - hwptr = li_read_hwptr(&rport->chan); - swptr = li_read_swptr(&rport->chan); - hw_avail = (hwptr - swptr + hwsize) % hwsize & -fragsize; - if (hw_avail > hwmax) - hw_avail = hwmax; - sw_avail = rport->swb_i_avail & -fragsize; - if (swstate != SW_RUN) { - DBGP("stopping. hwstate = %d\n", hwstate); - if (hwstate != HW_STOPPED) { - li_deactivate_dma(&rport->chan); - rport->hwstate = HW_STOPPED; - } - wake_up(&rport->queue); - break; - } - if (!sw_avail || !hw_avail) - break; - spin_unlock_irqrestore(&rport->lock, iflags); - - /* - * We gave up the port lock, but we have the HW_BUSY flag. - * Proceed without accessing any nonlocal state. - * Do not exit the loop -- must check for more work. - */ - - swidx = rport->swb_i_idx; - nb = hw_avail; - if (nb > sw_avail) - nb = sw_avail; - if (nb > hwsize - swptr) - nb = hwsize - swptr; /* don't overflow hwbuf */ - if (nb > swsize - swidx) - nb = swsize - swidx; /* don't overflow swbuf */ - ASSERT(nb > 0); - if (nb % fragsize) { - DBGP("nb = %d, fragsize = %d\n", nb, fragsize); - DBGP("hw_avail = %d\n", hw_avail); - DBGP("sw_avail = %d\n", sw_avail); - DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr); - DBGP("swsize = %d, swidx = %d\n", swsize, swidx); - } - ASSERT(!(nb % fragsize)); - DBGPV("copying hwb[%d..%d] to swb[%d..%d]\n", - swptr, swptr + nb, swidx, swidx + nb); - pcm_copy_in(rport, swidx, swptr, nb); - li_write_swptr(&rport->chan, (swptr + nb) % hwsize); - spin_lock_irqsave(&rport->lock, iflags); - __swb_inc_i(rport, nb); - rport->byte_count += nb; - rport->frag_count += nb / fragsize; - ASSERT(nb % fragsize == 0); - wake_up(&rport->queue); - } - rport->flags &= ~HW_BUSY; - spin_unlock_irqrestore(&rport->lock, iflags); - DBGRV(); -} - -/* - * pcm_flush_frag() writes zero samples to fill the current fragment, - * then flushes it to the hardware. - * - * It is only meaningful to flush output, not input. - */ - -static void pcm_flush_frag(vwsnd_dev_t *devc) -{ - vwsnd_port_t *wport = &devc->wport; - - DBGPV("swstate = %d\n", wport->swstate); - if (wport->swstate == SW_RUN) { - int idx = wport->swb_u_idx; - int end = (idx + wport->hw_fragsize - 1) - >> wport->hw_fragshift - << wport->hw_fragshift; - int nb = end - idx; - DBGPV("clearing %d bytes\n", nb); - if (nb) - memset(wport->swbuf + idx, - (char) wport->zero_word, - nb); - wport->swstate = SW_DRAIN; - pcm_output(devc, 0, nb); - } - DBGRV(); -} - -/* - * Wait for output to drain. This sleeps uninterruptibly because - * there is nothing intelligent we can do if interrupted. This - * means the process will be delayed in responding to the signal. - */ - -static void pcm_write_sync(vwsnd_dev_t *devc) -{ - vwsnd_port_t *wport = &devc->wport; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - vwsnd_port_hwstate_t hwstate; - - DBGEV("(devc=0x%p)\n", devc); - add_wait_queue(&wport->queue, &wait); - while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - spin_lock_irqsave(&wport->lock, flags); - { - hwstate = wport->hwstate; - } - spin_unlock_irqrestore(&wport->lock, flags); - if (hwstate == HW_STOPPED) - break; - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&wport->queue, &wait); - DBGPV("swstate = %d, hwstate = %d\n", wport->swstate, wport->hwstate); - DBGRV(); -} - -/*****************************************************************************/ -/* audio driver */ - -/* - * seek on an audio device always fails. - */ - -static void vwsnd_audio_read_intr(vwsnd_dev_t *devc, unsigned int status) -{ - int overflown = status & LI_INTR_COMM1_OVERFLOW; - - if (status & READ_INTR_MASK) - pcm_input(devc, overflown, 0); -} - -static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status) -{ - int underflown = status & LI_INTR_COMM2_UNDERFLOW; - - if (status & WRITE_INTR_MASK) - pcm_output(devc, underflown, 0); -} - -static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id) -{ - vwsnd_dev_t *devc = dev_id; - unsigned int status; - - DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id); - - status = li_get_clear_intr_status(&devc->lith); - vwsnd_audio_read_intr(devc, status); - vwsnd_audio_write_intr(devc, status); - return IRQ_HANDLED; -} - -static ssize_t vwsnd_audio_do_read(struct file *file, - char *buffer, - size_t count, - loff_t *ppos) -{ - vwsnd_dev_t *devc = file->private_data; - vwsnd_port_t *rport = ((file->f_mode & FMODE_READ) ? - &devc->rport : NULL); - int ret, nb; - - DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", - file, buffer, count, ppos); - - if (!rport) - return -EINVAL; - - if (rport->swbuf == NULL) { - vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? - &devc->wport : NULL; - ret = pcm_setup(devc, rport, wport); - if (ret < 0) - return ret; - } - - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - while (count) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&rport->queue, &wait); - while ((nb = swb_inc_u(rport, 0)) == 0) { - DBGPV("blocking\n"); - set_current_state(TASK_INTERRUPTIBLE); - if (rport->flags & DISABLED || - file->f_flags & O_NONBLOCK) { - current->state = TASK_RUNNING; - remove_wait_queue(&rport->queue, &wait); - return ret ? ret : -EAGAIN; - } - schedule(); - if (signal_pending(current)) { - current->state = TASK_RUNNING; - remove_wait_queue(&rport->queue, &wait); - return ret ? ret : -ERESTARTSYS; - } - } - current->state = TASK_RUNNING; - remove_wait_queue(&rport->queue, &wait); - pcm_input(devc, 0, 0); - /* nb bytes are available in userbuf. */ - if (nb > count) - nb = count; - DBGPV("nb = %d\n", nb); - if (copy_to_user(buffer, rport->swbuf + rport->swb_u_idx, nb)) - return -EFAULT; - (void) swb_inc_u(rport, nb); - buffer += nb; - count -= nb; - ret += nb; - } - DBGPV("returning %d\n", ret); - return ret; -} - -static ssize_t vwsnd_audio_read(struct file *file, - char *buffer, - size_t count, - loff_t *ppos) -{ - vwsnd_dev_t *devc = file->private_data; - ssize_t ret; - - mutex_lock(&devc->io_mutex); - ret = vwsnd_audio_do_read(file, buffer, count, ppos); - mutex_unlock(&devc->io_mutex); - return ret; -} - -static ssize_t vwsnd_audio_do_write(struct file *file, - const char *buffer, - size_t count, - loff_t *ppos) -{ - vwsnd_dev_t *devc = file->private_data; - vwsnd_port_t *wport = ((file->f_mode & FMODE_WRITE) ? - &devc->wport : NULL); - int ret, nb; - - DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n", - file, buffer, count, ppos); - - if (!wport) - return -EINVAL; - - if (wport->swbuf == NULL) { - vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? - &devc->rport : NULL; - ret = pcm_setup(devc, rport, wport); - if (ret < 0) - return ret; - } - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - while (count) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&wport->queue, &wait); - while ((nb = swb_inc_u(wport, 0)) == 0) { - set_current_state(TASK_INTERRUPTIBLE); - if (wport->flags & DISABLED || - file->f_flags & O_NONBLOCK) { - current->state = TASK_RUNNING; - remove_wait_queue(&wport->queue, &wait); - return ret ? ret : -EAGAIN; - } - schedule(); - if (signal_pending(current)) { - current->state = TASK_RUNNING; - remove_wait_queue(&wport->queue, &wait); - return ret ? ret : -ERESTARTSYS; - } - } - current->state = TASK_RUNNING; - remove_wait_queue(&wport->queue, &wait); - /* nb bytes are available in userbuf. */ - if (nb > count) - nb = count; - DBGPV("nb = %d\n", nb); - if (copy_from_user(wport->swbuf + wport->swb_u_idx, buffer, nb)) - return -EFAULT; - pcm_output(devc, 0, nb); - buffer += nb; - count -= nb; - ret += nb; - } - DBGPV("returning %d\n", ret); - return ret; -} - -static ssize_t vwsnd_audio_write(struct file *file, - const char *buffer, - size_t count, - loff_t *ppos) -{ - vwsnd_dev_t *devc = file->private_data; - ssize_t ret; - - mutex_lock(&devc->io_mutex); - ret = vwsnd_audio_do_write(file, buffer, count, ppos); - mutex_unlock(&devc->io_mutex); - return ret; -} - -/* No kernel lock - fine */ -static unsigned int vwsnd_audio_poll(struct file *file, - struct poll_table_struct *wait) -{ - vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; - vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? - &devc->rport : NULL; - vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? - &devc->wport : NULL; - unsigned int mask = 0; - - DBGEV("(file=0x%p, wait=0x%p)\n", file, wait); - - ASSERT(rport || wport); - if (rport) { - poll_wait(file, &rport->queue, wait); - if (swb_inc_u(rport, 0)) - mask |= (POLLIN | POLLRDNORM); - } - if (wport) { - poll_wait(file, &wport->queue, wait); - if (wport->swbuf == NULL || swb_inc_u(wport, 0)) - mask |= (POLLOUT | POLLWRNORM); - } - - DBGPV("returning 0x%x\n", mask); - return mask; -} - -static int vwsnd_audio_do_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg) -{ - vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; - vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ? - &devc->rport : NULL; - vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ? - &devc->wport : NULL; - vwsnd_port_t *aport = rport ? rport : wport; - struct audio_buf_info buf_info; - struct count_info info; - unsigned long flags; - int ival; - - - DBGEV("(file=0x%p, cmd=0x%x, arg=0x%lx)\n", - file, cmd, arg); - switch (cmd) { - case OSS_GETVERSION: /* _SIOR ('M', 118, int) */ - DBGX("OSS_GETVERSION\n"); - ival = SOUND_VERSION; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */ - DBGX("SNDCTL_DSP_GETCAPS\n"); - ival = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */ - DBGX("SNDCTL_DSP_GETFMTS\n"); - ival = (AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | - AFMT_U8 | AFMT_S8); - return put_user(ival, (int *) arg); - break; - - case SOUND_PCM_READ_RATE: /* _SIOR ('P', 2, int) */ - DBGX("SOUND_PCM_READ_RATE\n"); - ival = aport->sw_framerate; - return put_user(ival, (int *) arg); - - case SOUND_PCM_READ_CHANNELS: /* _SIOR ('P', 6, int) */ - DBGX("SOUND_PCM_READ_CHANNELS\n"); - ival = aport->sw_channels; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_SPEED %d\n", ival); - if (ival) { - if (aport->swstate != SW_INITIAL) { - DBGX("SNDCTL_DSP_SPEED failed: swstate = %d\n", - aport->swstate); - return -EINVAL; - } - if (ival < MIN_SPEED) - ival = MIN_SPEED; - if (ival > MAX_SPEED) - ival = MAX_SPEED; - if (rport) - rport->sw_framerate = ival; - if (wport) - wport->sw_framerate = ival; - } else - ival = aport->sw_framerate; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_STEREO %d\n", ival); - if (ival != 0 && ival != 1) - return -EINVAL; - if (aport->swstate != SW_INITIAL) - return -EINVAL; - if (rport) - rport->sw_channels = ival + 1; - if (wport) - wport->sw_channels = ival + 1; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_CHANNELS %d\n", ival); - if (ival != 1 && ival != 2) - return -EINVAL; - if (aport->swstate != SW_INITIAL) - return -EINVAL; - if (rport) - rport->sw_channels = ival; - if (wport) - wport->sw_channels = ival; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */ - ival = pcm_setup(devc, rport, wport); - if (ival < 0) { - DBGX("SNDCTL_DSP_GETBLKSIZE failed, errno %d\n", ival); - return ival; - } - ival = 1 << aport->sw_fragshift; - DBGX("SNDCTL_DSP_GETBLKSIZE returning %d\n", ival); - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n", - ival >> 16, ival & 0xFFFF); - if (aport->swstate != SW_INITIAL) - return -EINVAL; - { - int sw_fragshift = ival & 0xFFFF; - int sw_subdivshift = aport->sw_subdivshift; - int hw_fragshift = sw_fragshift - sw_subdivshift; - int sw_fragcount = (ival >> 16) & 0xFFFF; - int hw_fragsize; - if (hw_fragshift < MIN_FRAGSHIFT) - hw_fragshift = MIN_FRAGSHIFT; - if (hw_fragshift > MAX_FRAGSHIFT) - hw_fragshift = MAX_FRAGSHIFT; - sw_fragshift = hw_fragshift + aport->sw_subdivshift; - hw_fragsize = 1 << hw_fragshift; - if (sw_fragcount < MIN_FRAGCOUNT(hw_fragsize)) - sw_fragcount = MIN_FRAGCOUNT(hw_fragsize); - if (sw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) - sw_fragcount = MAX_FRAGCOUNT(hw_fragsize); - DBGPV("sw_fragshift = %d\n", sw_fragshift); - DBGPV("rport = 0x%p, wport = 0x%p\n", rport, wport); - if (rport) { - rport->sw_fragshift = sw_fragshift; - rport->sw_fragcount = sw_fragcount; - } - if (wport) { - wport->sw_fragshift = sw_fragshift; - wport->sw_fragcount = sw_fragcount; - } - ival = sw_fragcount << 16 | sw_fragshift; - } - DBGX("SNDCTL_DSP_SETFRAGMENT returns %d:%d\n", - ival >> 16, ival & 0xFFFF); - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_SUBDIVIDE %d\n", ival); - if (aport->swstate != SW_INITIAL) - return -EINVAL; - { - int subdivshift; - int hw_fragshift, hw_fragsize, hw_fragcount; - switch (ival) { - case 1: subdivshift = 0; break; - case 2: subdivshift = 1; break; - case 4: subdivshift = 2; break; - default: return -EINVAL; - } - hw_fragshift = aport->sw_fragshift - subdivshift; - if (hw_fragshift < MIN_FRAGSHIFT || - hw_fragshift > MAX_FRAGSHIFT) - return -EINVAL; - hw_fragsize = 1 << hw_fragshift; - hw_fragcount = aport->sw_fragcount >> subdivshift; - if (hw_fragcount < MIN_FRAGCOUNT(hw_fragsize) || - hw_fragcount > MAX_FRAGCOUNT(hw_fragsize)) - return -EINVAL; - if (rport) - rport->sw_subdivshift = subdivshift; - if (wport) - wport->sw_subdivshift = subdivshift; - } - return 0; - - case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_SETFMT %d\n", ival); - if (ival != AFMT_QUERY) { - if (aport->swstate != SW_INITIAL) { - DBGP("SETFMT failed, swstate = %d\n", - aport->swstate); - return -EINVAL; - } - switch (ival) { - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - case AFMT_S16_LE: - if (rport) - rport->sw_samplefmt = ival; - if (wport) - wport->sw_samplefmt = ival; - break; - default: - return -EINVAL; - } - } - ival = aport->sw_samplefmt; - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */ - DBGXV("SNDCTL_DSP_GETOSPACE\n"); - if (!wport) - return -EINVAL; - ival = pcm_setup(devc, rport, wport); - if (ival < 0) - return ival; - ival = swb_inc_u(wport, 0); - buf_info.fragments = ival >> wport->sw_fragshift; - buf_info.fragstotal = wport->sw_fragcount; - buf_info.fragsize = 1 << wport->sw_fragshift; - buf_info.bytes = ival; - DBGXV("SNDCTL_DSP_GETOSPACE returns { %d %d %d %d }\n", - buf_info.fragments, buf_info.fragstotal, - buf_info.fragsize, buf_info.bytes); - if (copy_to_user((void *) arg, &buf_info, sizeof buf_info)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */ - DBGX("SNDCTL_DSP_GETISPACE\n"); - if (!rport) - return -EINVAL; - ival = pcm_setup(devc, rport, wport); - if (ival < 0) - return ival; - ival = swb_inc_u(rport, 0); - buf_info.fragments = ival >> rport->sw_fragshift; - buf_info.fragstotal = rport->sw_fragcount; - buf_info.fragsize = 1 << rport->sw_fragshift; - buf_info.bytes = ival; - DBGX("SNDCTL_DSP_GETISPACE returns { %d %d %d %d }\n", - buf_info.fragments, buf_info.fragstotal, - buf_info.fragsize, buf_info.bytes); - if (copy_to_user((void *) arg, &buf_info, sizeof buf_info)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ - DBGX("SNDCTL_DSP_NONBLOCK\n"); - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ - DBGX("SNDCTL_DSP_RESET\n"); - /* - * Nothing special needs to be done for input. Input - * samples sit in swbuf, but it will be reinitialized - * to empty when pcm_setup() is called. - */ - if (wport && wport->swbuf) { - wport->swstate = SW_INITIAL; - pcm_output(devc, 0, 0); - pcm_write_sync(devc); - } - pcm_shutdown(devc, rport, wport); - return 0; - - case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */ - DBGX("SNDCTL_DSP_SYNC\n"); - if (wport) { - pcm_flush_frag(devc); - pcm_write_sync(devc); - } - pcm_shutdown(devc, rport, wport); - return 0; - - case SNDCTL_DSP_POST: /* _SIO ('P', 8) */ - DBGX("SNDCTL_DSP_POST\n"); - if (!wport) - return -EINVAL; - pcm_flush_frag(devc); - return 0; - - case SNDCTL_DSP_GETIPTR: /* _SIOR ('P', 17, count_info) */ - DBGX("SNDCTL_DSP_GETIPTR\n"); - if (!rport) - return -EINVAL; - spin_lock_irqsave(&rport->lock, flags); - { - ustmsc_t ustmsc; - if (rport->hwstate == HW_RUNNING) { - ASSERT(rport->swstate == SW_RUN); - li_read_USTMSC(&rport->chan, &ustmsc); - info.bytes = ustmsc.msc - rport->MSC_offset; - info.bytes *= rport->frame_size; - } else { - info.bytes = rport->byte_count; - } - info.blocks = rport->frag_count; - info.ptr = 0; /* not implemented */ - rport->frag_count = 0; - } - spin_unlock_irqrestore(&rport->lock, flags); - if (copy_to_user((void *) arg, &info, sizeof info)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */ - DBGX("SNDCTL_DSP_GETOPTR\n"); - if (!wport) - return -EINVAL; - spin_lock_irqsave(&wport->lock, flags); - { - ustmsc_t ustmsc; - if (wport->hwstate == HW_RUNNING) { - ASSERT(wport->swstate == SW_RUN); - li_read_USTMSC(&wport->chan, &ustmsc); - info.bytes = ustmsc.msc - wport->MSC_offset; - info.bytes *= wport->frame_size; - } else { - info.bytes = wport->byte_count; - } - info.blocks = wport->frag_count; - info.ptr = 0; /* not implemented */ - wport->frag_count = 0; - } - spin_unlock_irqrestore(&wport->lock, flags); - if (copy_to_user((void *) arg, &info, sizeof info)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */ - DBGX("SNDCTL_DSP_GETODELAY\n"); - if (!wport) - return -EINVAL; - spin_lock_irqsave(&wport->lock, flags); - { - int fsize = wport->frame_size; - ival = wport->swb_i_avail / fsize; - if (wport->hwstate == HW_RUNNING) { - int swptr, hwptr, hwframes, hwbytes, hwsize; - int totalhwbytes; - ustmsc_t ustmsc; - - hwsize = wport->hwbuf_size; - swptr = li_read_swptr(&wport->chan); - li_read_USTMSC(&wport->chan, &ustmsc); - hwframes = ustmsc.msc - wport->MSC_offset; - totalhwbytes = hwframes * fsize; - hwptr = totalhwbytes % hwsize; - hwbytes = (swptr - hwptr + hwsize) % hwsize; - ival += hwbytes / fsize; - } - } - spin_unlock_irqrestore(&wport->lock, flags); - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_PROFILE: /* _SIOW ('P', 23, int) */ - DBGX("SNDCTL_DSP_PROFILE\n"); - - /* - * Thomas Sailer explains SNDCTL_DSP_PROFILE - * (private email, March 24, 1999): - * - * This gives the sound driver a hint on what it - * should do with partial fragments - * (i.e. fragments partially filled with write). - * This can direct the driver to zero them or - * leave them alone. But don't ask me what this - * is good for, my driver just zeroes the last - * fragment before the receiver stops, no idea - * what good for any other behaviour could - * be. Implementing it as NOP seems safe. - */ - - break; - - case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */ - DBGX("SNDCTL_DSP_GETTRIGGER\n"); - ival = 0; - if (rport) { - spin_lock_irqsave(&rport->lock, flags); - { - if (!(rport->flags & DISABLED)) - ival |= PCM_ENABLE_INPUT; - } - spin_unlock_irqrestore(&rport->lock, flags); - } - if (wport) { - spin_lock_irqsave(&wport->lock, flags); - { - if (!(wport->flags & DISABLED)) - ival |= PCM_ENABLE_OUTPUT; - } - spin_unlock_irqrestore(&wport->lock, flags); - } - return put_user(ival, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */ - if (get_user(ival, (int *) arg)) - return -EFAULT; - DBGX("SNDCTL_DSP_SETTRIGGER %d\n", ival); - - /* - * If user is disabling I/O and port is not in initial - * state, fail with EINVAL. - */ - - if (((rport && !(ival & PCM_ENABLE_INPUT)) || - (wport && !(ival & PCM_ENABLE_OUTPUT))) && - aport->swstate != SW_INITIAL) - return -EINVAL; - - if (rport) { - vwsnd_port_hwstate_t hwstate; - spin_lock_irqsave(&rport->lock, flags); - { - hwstate = rport->hwstate; - if (ival & PCM_ENABLE_INPUT) - rport->flags &= ~DISABLED; - else - rport->flags |= DISABLED; - } - spin_unlock_irqrestore(&rport->lock, flags); - if (hwstate != HW_RUNNING && ival & PCM_ENABLE_INPUT) { - - if (rport->swstate == SW_INITIAL) - pcm_setup(devc, rport, wport); - else - li_activate_dma(&rport->chan); - } - } - if (wport) { - vwsnd_port_flags_t pflags; - spin_lock_irqsave(&wport->lock, flags); - { - pflags = wport->flags; - if (ival & PCM_ENABLE_OUTPUT) - wport->flags &= ~DISABLED; - else - wport->flags |= DISABLED; - } - spin_unlock_irqrestore(&wport->lock, flags); - if (pflags & DISABLED && ival & PCM_ENABLE_OUTPUT) { - if (wport->swstate == SW_RUN) - pcm_output(devc, 0, 0); - } - } - return 0; - - default: - DBGP("unknown ioctl 0x%x\n", cmd); - return -EINVAL; - } - DBGP("unimplemented ioctl 0x%x\n", cmd); - return -EINVAL; -} - -static long vwsnd_audio_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg) -{ - vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; - int ret; - - mutex_lock(&vwsnd_mutex); - mutex_lock(&devc->io_mutex); - ret = vwsnd_audio_do_ioctl(file, cmd, arg); - mutex_unlock(&devc->io_mutex); - mutex_unlock(&vwsnd_mutex); - - return ret; -} - -/* No mmap. */ - -static int vwsnd_audio_mmap(struct file *file, struct vm_area_struct *vma) -{ - DBGE("(file=0x%p, vma=0x%p)\n", file, vma); - return -ENODEV; -} - -/* - * Open the audio device for read and/or write. - * - * Returns 0 on success, -errno on failure. - */ - -static int vwsnd_audio_open(struct inode *inode, struct file *file) -{ - vwsnd_dev_t *devc; - int minor = iminor(inode); - int sw_samplefmt; - DEFINE_WAIT(wait); - - DBGE("(inode=0x%p, file=0x%p)\n", inode, file); - - mutex_lock(&vwsnd_mutex); - INC_USE_COUNT; - for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) - if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) - break; - - if (devc == NULL) { - DEC_USE_COUNT; - mutex_unlock(&vwsnd_mutex); - return -ENODEV; - } - - mutex_lock(&devc->open_mutex); - while (1) { - prepare_to_wait(&devc->open_wait, &wait, TASK_INTERRUPTIBLE); - if (!(devc->open_mode & file->f_mode)) - break; - - mutex_unlock(&devc->open_mutex); - mutex_unlock(&vwsnd_mutex); - if (file->f_flags & O_NONBLOCK) { - DEC_USE_COUNT; - return -EBUSY; - } - schedule(); - if (signal_pending(current)) { - DEC_USE_COUNT; - return -ERESTARTSYS; - } - mutex_lock(&vwsnd_mutex); - mutex_lock(&devc->open_mutex); - } - finish_wait(&devc->open_wait, &wait); - devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&devc->open_mutex); - - /* get default sample format from minor number. */ - - sw_samplefmt = 0; - if ((minor & 0xF) == SND_DEV_DSP) - sw_samplefmt = AFMT_U8; - else if ((minor & 0xF) == SND_DEV_AUDIO) - sw_samplefmt = AFMT_MU_LAW; - else if ((minor & 0xF) == SND_DEV_DSP16) - sw_samplefmt = AFMT_S16_LE; - else - ASSERT(0); - - /* Initialize vwsnd_ports. */ - - mutex_lock(&devc->io_mutex); - { - if (file->f_mode & FMODE_READ) { - devc->rport.swstate = SW_INITIAL; - devc->rport.flags = 0; - devc->rport.sw_channels = 1; - devc->rport.sw_samplefmt = sw_samplefmt; - devc->rport.sw_framerate = 8000; - devc->rport.sw_fragshift = DEFAULT_FRAGSHIFT; - devc->rport.sw_fragcount = DEFAULT_FRAGCOUNT; - devc->rport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; - devc->rport.byte_count = 0; - devc->rport.frag_count = 0; - } - if (file->f_mode & FMODE_WRITE) { - devc->wport.swstate = SW_INITIAL; - devc->wport.flags = 0; - devc->wport.sw_channels = 1; - devc->wport.sw_samplefmt = sw_samplefmt; - devc->wport.sw_framerate = 8000; - devc->wport.sw_fragshift = DEFAULT_FRAGSHIFT; - devc->wport.sw_fragcount = DEFAULT_FRAGCOUNT; - devc->wport.sw_subdivshift = DEFAULT_SUBDIVSHIFT; - devc->wport.byte_count = 0; - devc->wport.frag_count = 0; - } - } - mutex_unlock(&devc->io_mutex); - - file->private_data = devc; - DBGRV(); - mutex_unlock(&vwsnd_mutex); - return 0; -} - -/* - * Release (close) the audio device. - */ - -static int vwsnd_audio_release(struct inode *inode, struct file *file) -{ - vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; - vwsnd_port_t *wport = NULL, *rport = NULL; - int err = 0; - - mutex_lock(&vwsnd_mutex); - mutex_lock(&devc->io_mutex); - { - DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); - - if (file->f_mode & FMODE_READ) - rport = &devc->rport; - if (file->f_mode & FMODE_WRITE) { - wport = &devc->wport; - pcm_flush_frag(devc); - pcm_write_sync(devc); - } - pcm_shutdown(devc, rport, wport); - if (rport) - rport->swstate = SW_OFF; - if (wport) - wport->swstate = SW_OFF; - } - mutex_unlock(&devc->io_mutex); - - mutex_lock(&devc->open_mutex); - { - devc->open_mode &= ~file->f_mode; - } - mutex_unlock(&devc->open_mutex); - wake_up(&devc->open_wait); - DEC_USE_COUNT; - DBGR(); - mutex_unlock(&vwsnd_mutex); - return err; -} - -static const struct file_operations vwsnd_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = vwsnd_audio_read, - .write = vwsnd_audio_write, - .poll = vwsnd_audio_poll, - .unlocked_ioctl = vwsnd_audio_ioctl, - .mmap = vwsnd_audio_mmap, - .open = vwsnd_audio_open, - .release = vwsnd_audio_release, -}; - -/*****************************************************************************/ -/* mixer driver */ - -/* open the mixer device. */ - -static int vwsnd_mixer_open(struct inode *inode, struct file *file) -{ - vwsnd_dev_t *devc; - - DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); - - INC_USE_COUNT; - mutex_lock(&vwsnd_mutex); - for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) - if (devc->mixer_minor == iminor(inode)) - break; - - if (devc == NULL) { - DEC_USE_COUNT; - mutex_unlock(&vwsnd_mutex); - return -ENODEV; - } - file->private_data = devc; - mutex_unlock(&vwsnd_mutex); - return 0; -} - -/* release (close) the mixer device. */ - -static int vwsnd_mixer_release(struct inode *inode, struct file *file) -{ - DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); - DEC_USE_COUNT; - return 0; -} - -/* mixer_read_ioctl handles all read ioctls on the mixer device. */ - -static int mixer_read_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg) -{ - int val = -1; - - DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); - - switch (nr) { - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - case SOUND_MIXER_DEVMASK: - val = (SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); - break; - - case SOUND_MIXER_STEREODEVS: - val = (SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV); - break; - - case SOUND_MIXER_OUTMASK: - val = (SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_MIC | SOUND_MASK_CD); - break; - - case SOUND_MIXER_RECMASK: - val = (SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_MIC | SOUND_MASK_CD); - break; - - case SOUND_MIXER_PCM: - val = ad1843_get_gain(&devc->lith, &ad1843_gain_PCM); - break; - - case SOUND_MIXER_LINE: - val = ad1843_get_gain(&devc->lith, &ad1843_gain_LINE); - break; - - case SOUND_MIXER_MIC: - val = ad1843_get_gain(&devc->lith, &ad1843_gain_MIC); - break; - - case SOUND_MIXER_CD: - val = ad1843_get_gain(&devc->lith, &ad1843_gain_CD); - break; - - case SOUND_MIXER_RECLEV: - val = ad1843_get_gain(&devc->lith, &ad1843_gain_RECLEV); - break; - - case SOUND_MIXER_RECSRC: - val = ad1843_get_recsrc(&devc->lith); - break; - - case SOUND_MIXER_OUTSRC: - val = ad1843_get_outsrc(&devc->lith); - break; - - default: - return -EINVAL; - } - return put_user(val, (int __user *) arg); -} - -/* mixer_write_ioctl handles all write ioctls on the mixer device. */ - -static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg) -{ - int val; - int err; - - DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg); - - err = get_user(val, (int __user *) arg); - if (err) - return -EFAULT; - switch (nr) { - case SOUND_MIXER_PCM: - val = ad1843_set_gain(&devc->lith, &ad1843_gain_PCM, val); - break; - - case SOUND_MIXER_LINE: - val = ad1843_set_gain(&devc->lith, &ad1843_gain_LINE, val); - break; - - case SOUND_MIXER_MIC: - val = ad1843_set_gain(&devc->lith, &ad1843_gain_MIC, val); - break; - - case SOUND_MIXER_CD: - val = ad1843_set_gain(&devc->lith, &ad1843_gain_CD, val); - break; - - case SOUND_MIXER_RECLEV: - val = ad1843_set_gain(&devc->lith, &ad1843_gain_RECLEV, val); - break; - - case SOUND_MIXER_RECSRC: - if (devc->rport.swbuf || devc->wport.swbuf) - return -EBUSY; /* can't change recsrc while running */ - val = ad1843_set_recsrc(&devc->lith, val); - break; - - case SOUND_MIXER_OUTSRC: - val = ad1843_set_outsrc(&devc->lith, val); - break; - - default: - return -EINVAL; - } - if (val < 0) - return val; - return put_user(val, (int __user *) arg); -} - -/* This is the ioctl entry to the mixer driver. */ - -static long vwsnd_mixer_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg) -{ - vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; - const unsigned int nrmask = _IOC_NRMASK << _IOC_NRSHIFT; - const unsigned int nr = (cmd & nrmask) >> _IOC_NRSHIFT; - int retval; - - DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); - - mutex_lock(&vwsnd_mutex); - mutex_lock(&devc->mix_mutex); - { - if ((cmd & ~nrmask) == MIXER_READ(0)) - retval = mixer_read_ioctl(devc, nr, (void __user *) arg); - else if ((cmd & ~nrmask) == MIXER_WRITE(0)) - retval = mixer_write_ioctl(devc, nr, (void __user *) arg); - else - retval = -EINVAL; - } - mutex_unlock(&devc->mix_mutex); - mutex_unlock(&vwsnd_mutex); - return retval; -} - -static const struct file_operations vwsnd_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = vwsnd_mixer_ioctl, - .open = vwsnd_mixer_open, - .release = vwsnd_mixer_release, -}; - -/*****************************************************************************/ -/* probe/attach/unload */ - -/* driver probe routine. Return nonzero if hardware is found. */ - -static int __init probe_vwsnd(struct address_info *hw_config) -{ - lithium_t lith; - int w; - unsigned long later; - - DBGEV("(hw_config=0x%p)\n", hw_config); - - /* XXX verify lithium present (to prevent crash on non-vw) */ - - if (li_create(&lith, hw_config->io_base) != 0) { - printk(KERN_WARNING "probe_vwsnd: can't map lithium\n"); - return 0; - } - later = jiffies + 2; - li_writel(&lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE); - do { - w = li_readl(&lith, LI_HOST_CONTROLLER); - } while (w == LI_HC_LINK_ENABLE && time_before(jiffies, later)); - - li_destroy(&lith); - - DBGPV("HC = 0x%04x\n", w); - - if ((w == LI_HC_LINK_ENABLE) || (w & LI_HC_LINK_CODEC)) { - - /* This may indicate a beta machine with no audio, - * or a future machine with different audio. - * On beta-release 320 w/ no audio, HC == 0x4000 */ - - printk(KERN_WARNING "probe_vwsnd: audio codec not found\n"); - return 0; - } - - if (w & LI_HC_LINK_FAILURE) { - printk(KERN_WARNING "probe_vwsnd: can't init audio codec\n"); - return 0; - } - - printk(KERN_INFO "vwsnd: lithium audio at mmio %#x irq %d\n", - hw_config->io_base, hw_config->irq); - - return 1; -} - -/* - * driver attach routine. Initialize driver data structures and - * initialize hardware. A new vwsnd_dev_t is allocated and put - * onto the global list, vwsnd_dev_list. - * - * Return +minor_dev on success, -errno on failure. - */ - -static int __init attach_vwsnd(struct address_info *hw_config) -{ - vwsnd_dev_t *devc = NULL; - int err = -ENOMEM; - - DBGEV("(hw_config=0x%p)\n", hw_config); - - devc = kmalloc(sizeof (vwsnd_dev_t), GFP_KERNEL); - if (devc == NULL) - goto fail0; - - err = li_create(&devc->lith, hw_config->io_base); - if (err) - goto fail1; - - init_waitqueue_head(&devc->open_wait); - - devc->rport.hwbuf_size = HWBUF_SIZE; - devc->rport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); - if (!devc->rport.hwbuf_vaddr) - goto fail2; - devc->rport.hwbuf = (void *) devc->rport.hwbuf_vaddr; - devc->rport.hwbuf_paddr = virt_to_phys(devc->rport.hwbuf); - - /* - * Quote from the NT driver: - * - * // WARNING!!! HACK to setup output dma!!! - * // This is required because even on output there is some data - * // trickling into the input DMA channel. This is a bug in the - * // Lithium microcode. - * // --sde - * - * We set the input side's DMA base address here. It will remain - * valid until the driver is unloaded. - */ - - li_writel(&devc->lith, LI_COMM1_BASE, - devc->rport.hwbuf_paddr >> 8 | 1 << (37 - 8)); - - devc->wport.hwbuf_size = HWBUF_SIZE; - devc->wport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER); - if (!devc->wport.hwbuf_vaddr) - goto fail3; - devc->wport.hwbuf = (void *) devc->wport.hwbuf_vaddr; - devc->wport.hwbuf_paddr = virt_to_phys(devc->wport.hwbuf); - DBGP("wport hwbuf = 0x%p\n", devc->wport.hwbuf); - - DBGDO(shut_up++); - err = ad1843_init(&devc->lith); - DBGDO(shut_up--); - if (err) - goto fail4; - - /* install interrupt handler */ - - err = request_irq(hw_config->irq, vwsnd_audio_intr, 0, "vwsnd", devc); - if (err) - goto fail5; - - /* register this device's drivers. */ - - devc->audio_minor = register_sound_dsp(&vwsnd_audio_fops, -1); - if ((err = devc->audio_minor) < 0) { - DBGDO(printk(KERN_WARNING - "attach_vwsnd: register_sound_dsp error %d\n", - err)); - goto fail6; - } - devc->mixer_minor = register_sound_mixer(&vwsnd_mixer_fops, - devc->audio_minor >> 4); - if ((err = devc->mixer_minor) < 0) { - DBGDO(printk(KERN_WARNING - "attach_vwsnd: register_sound_mixer error %d\n", - err)); - goto fail7; - } - - /* Squirrel away device indices for unload routine. */ - - hw_config->slots[0] = devc->audio_minor; - - /* Initialize as much of *devc as possible */ - - mutex_init(&devc->open_mutex); - mutex_init(&devc->io_mutex); - mutex_init(&devc->mix_mutex); - devc->open_mode = 0; - spin_lock_init(&devc->rport.lock); - init_waitqueue_head(&devc->rport.queue); - devc->rport.swstate = SW_OFF; - devc->rport.hwstate = HW_STOPPED; - devc->rport.flags = 0; - devc->rport.swbuf = NULL; - spin_lock_init(&devc->wport.lock); - init_waitqueue_head(&devc->wport.queue); - devc->wport.swstate = SW_OFF; - devc->wport.hwstate = HW_STOPPED; - devc->wport.flags = 0; - devc->wport.swbuf = NULL; - - /* Success. Link us onto the local device list. */ - - devc->next_dev = vwsnd_dev_list; - vwsnd_dev_list = devc; - return devc->audio_minor; - - /* So many ways to fail. Undo what we did. */ - - fail7: - unregister_sound_dsp(devc->audio_minor); - fail6: - free_irq(hw_config->irq, devc); - fail5: - fail4: - free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); - fail3: - free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); - fail2: - li_destroy(&devc->lith); - fail1: - kfree(devc); - fail0: - return err; -} - -static int __exit unload_vwsnd(struct address_info *hw_config) -{ - vwsnd_dev_t *devc, **devcp; - - DBGE("()\n"); - - devcp = &vwsnd_dev_list; - while ((devc = *devcp)) { - if (devc->audio_minor == hw_config->slots[0]) { - *devcp = devc->next_dev; - break; - } - devcp = &devc->next_dev; - } - - if (!devc) - return -ENODEV; - - unregister_sound_mixer(devc->mixer_minor); - unregister_sound_dsp(devc->audio_minor); - free_irq(hw_config->irq, devc); - free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER); - free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER); - li_destroy(&devc->lith); - kfree(devc); - - return 0; -} - -/*****************************************************************************/ -/* initialization and loadable kernel module interface */ - -static struct address_info the_hw_config = { - 0xFF001000, /* lithium phys addr */ - CO_IRQ(CO_APIC_LI_AUDIO) /* irq */ -}; - -MODULE_DESCRIPTION("SGI Visual Workstation sound module"); -MODULE_AUTHOR("Bob Miller <kbob@sgi.com>"); -MODULE_LICENSE("GPL"); - -static int __init init_vwsnd(void) -{ - int err; - - DBGXV("\n"); - DBGXV("sound::vwsnd::init_module()\n"); - - if (!probe_vwsnd(&the_hw_config)) - return -ENODEV; - - err = attach_vwsnd(&the_hw_config); - if (err < 0) - return err; - return 0; -} - -static void __exit cleanup_vwsnd(void) -{ - DBGX("sound::vwsnd::cleanup_module()\n"); - - unload_vwsnd(&the_hw_config); -} - -module_init(init_vwsnd); -module_exit(cleanup_vwsnd); |