diff options
Diffstat (limited to 'xc/programs/Xserver/hw/xfree86')
59 files changed, 12145 insertions, 2536 deletions
diff --git a/xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml b/xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml index 895ce09a7..e95ff113a 100644 --- a/xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml +++ b/xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml @@ -3,17 +3,17 @@ ]> <!-- Created: Mon Feb 28 13:00:00 2000 by brian@precisioninsight.com --> -<!-- Revised: Mon Mar 6 20:10:02 2000 by kevin@precisioninsight.com --> +<!-- Revised: Fri May 19 09:41:48 2000 by martin@valinux.com --> <article> - <title>DRI Users Guide + <title>DRI User Guide <author><htmlurl url="http://www.precisioninsight.com/" name="Precision Insight, Inc."> - <date>6 March 2000 + <date>18 May 2000 <ident> - $XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml,v 1.3 2000/03/08 05:38:41 dawes Exp $ + $XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml,v 1.3 2000/04/05 05:38:41 brianp Exp $ </ident> <toc> @@ -25,7 +25,7 @@ <bf>Copyright © 2000 by Precision Insight, Inc., Cedar Park, Texas. All Rights Reserved.</bf> - <p> +<p> <bf>Permission is granted to make and distribute verbatim copies of this document provided the copyright notice and this permission notice are preserved on all copies.</bf> @@ -43,6 +43,8 @@ trademarks of 3Dlabs Inc. Ltd. 3dfx, Voodoo3, Voodoo4, and Voodoo5 are registered trademarks of 3dfx Interactive, Incorporated. + Matrox is a registered trademark of Matrox Electronic Systems Ltd. + ATI Rage is a registered trademark of ATI Technologies, Inc. All other trademarks mentioned are the property of their respective owners. @@ -60,9 +62,13 @@ software downloads. <p> This document does not cover compilation or installation of - XFree86 4.0; - it is assumed that you've already installed a Linux distribution which - includes XFree86 4.0. + XFree86 4.0. + It is assumed that you've already installed a Linux distribution which + includes XFree86 4.0 or that you're an experienced Linux developer + who has compiled the DRI for himself. + DRI download, compilation and installation instructions can be found + at <htmlurl url="http://dri.sourceforge.net/DRIcompile.html" + name="http://dri.sourceforge.net/DRIcompile.html"> <sect>Supported Hardware <p> @@ -71,8 +77,8 @@ Support for Alpha, and perhaps other CPUs, should be available in the future. <p> - XFree86 4.0 includes 3D acceleration for the following - graphics hardware: + XFree86 4.0 (or later versions) includes 3D acceleration for the + following graphics hardware: <itemize> <item>3dfx: @@ -87,6 +93,19 @@ </itemize> There are many configurations of 3dfx cards on the market. Not all have been tested. + <item>Matrox G400 + <item>ATI Rage 128 + <itemize> + <item>Rage Fury AGP + <item>Rage Magnum AGP + <item>XPERT 2000 AGP + <item>XPERT 128 AGP + <item>XPERT 99 AGP + <item>All-in-Wonder 128 AGP + </itemize> + The PCI versions of these cards also have minimal support. + Note that there are also Rage 128 Pro based boards on the + market, and these are not yet supported. <item>3Dlabs Oxygen GMX 2000 (MX/Gamma based) </itemize> @@ -94,8 +113,6 @@ Support for the following hardware is underway: <itemize> <item>Intel i810 - <item>Matrox G400 - <item>ATI Rage 128 <item>3dfx Voodoo4 and Voodoo5 series </itemize> @@ -104,8 +121,10 @@ <p> <itemize> <item>XFree86 4.0 - <item>Linux kernel 2.2.x (later kernels will be supported in + <item>For the 3dfx Voodoo3 driver, Linux kernel 2.2.x (later + kernels will be supported in the near future, and may be required for some chipsets) + <item>For the Matrox G400, Linux kernel 2.3.51, with AGP support </itemize> <p> Mesa 3.3 (beta) is included with XFree86 4.0; there is no need to @@ -119,20 +138,17 @@ <sect1>Kernel module <p> - Before starting the X server you must install the correct kernel - module for your hardware. - <p> - This can be done by executing the following as root: - <verb> - insmod XXX/drivername.o - </verb> - <p> - For example, on 3dfx hardware, the kernel module is called tdfx.o - so you you would type insmod XXX/tdfx.o - - <p> - Verify that the kernel module was installed by checking that - /proc/dri/0 exists. + XFree86 4.0.1 added automatic kernel module loading to the X server. + On Linux, the X server uses modprobe to load kernel modules. + The DRM kernel modules should be in /lib/modules/KERNEL-VERSION/misc/ + for automatic loading to work. +<p> + Optionally, DRM kernel modules can be loaded manually with insmod + prior to starting the X server. +<p> + You can verify that the kernel module was installed with lsmod, + checking the X server startup log, and checking that /proc/dri/0 + exists. <sect1>XF86Config file <p> @@ -199,6 +215,7 @@ <p> Next, the Device section of the XF86Config file must describe your particular hardware. + <p> For example, here's the Device section for a 3dfx Voodoo3 card: <verb> @@ -210,6 +227,27 @@ </verb> <p> + Here's the Device section for a Matrox G400 card: + <verb> + Section "Device" + Identifier "G400" + VendorName "Matrox" + Driver "mga" + VideoRam 32768 + EndSection + </verb> + + <p> + Here's the Device section for an ATI Rage 128 card: + <verb> + Section "Device" + Identifier "Rage128" + VendorName "ATI" + Driver "r128" + EndSection + </verb> + + <p> Finally, the Screen section of the XF86Config file may have to be specially configured as well. For example, Voodoo3 hardware acceleration is only available @@ -227,7 +265,10 @@ EndSubsection EndSection </verb> - + <p> + Replace <em>Voodoo3</em> with <em>G400</em> for Matrox G400. + <p> + Replace <em>Voodoo3</em> with <em>Rage128</em> for ATI Rage 128. <p> If there are errors in the XF86Config file, the X server will log errors to the file /var/log/XFree86.0.log @@ -301,6 +342,25 @@ if means that the libGL.so.1 file is not the right location. Proceed to the trouble shooting section. + <sect1>libOSMesa.so +<p> + OSMesa (Off-Screen Mesa) is an interface and driver for rendering + 3D images into a user-allocated block of memory rather than an + on-screen window. +<p> + libOSMesa.so implements the OSMesa interface and must be linked + with your application if you want to use the OSMesa functions. + You must also link with libGL.so. For example: + <verb> + gcc osdemo.c -L/usr/X11R6/lib -lOSMesa -lGLU -lGL -o osdemo + </verb> +<p> + In stand-alone Mesa this interface was compiled into the monolithic + libGL.so (formerly libMesaGL.so) library. + In XFree86 4.0.1 and later this interface is implemented in a + separate library. +<p> + <sect1>glxinfo <p> glxinfo is a useful program for checking which version of @@ -346,20 +406,25 @@ <enum> <item> <tt/LIBGL_DEBUG/, if defined will cause libGL.so to print error - and diagnostic messages. This can help to solve problems. + and diagnostic messages. + This can help to solve problems. + Setting <tt/LIBGL_DEBUG/ to <tt/verbose/ may provide additional + information. <item> <tt/LIBGL_ALWAYS_INDIRECT/, if defined this will force libGL.so to always use indirect rendering instead of hardware - acceleration. + acceleration. This can be useful to isolate rendering errors. <item> - <tt/LIBGL_DRIVERS_DIR/ can be used to override the default - directory which is searched for 3D drivers. + <tt/LIBGL_DRIVERS_PATH/ can be used to override the default + directories which are searched for 3D drivers. + The value is one or more paths separated by colons. In a typical XFree86 installation, the 3D drivers should be in - /usr/X11R6/lib/modules/dri/. - This environment variable can be used to specify a different - directory. + /usr/X11R6/lib/modules/dri/ and <tt/LIBGL_DRIVERS_PATH/ need + not be defined. Note that this feature is disabled for set-uid programs. + This variable replaces the <tt/LIBGL_DRIVERS_DIR/ env var used + in XFree86 4.0. </enum> <p> Mesa-based drivers (this includes most of the drivers listed @@ -531,6 +596,40 @@ <sect1>3dfx Voodoo3 <p> + <sect2>Configuration +<p> + Your XF86Config file's device section must specify the + <tt>tdfx</tt> device: + <verb> + Section "Device" + Identifier "Voodoo3" + VendorName "3dfx" + Driver "tdfx" + EndSection + </verb> + The Screen section should then reference the Voodoo3 device: + <verb> + Section "Screen" + Identifier "Screen 1" + Device "Voodoo3" + Monitor "High Res Monitor" + DefaultDepth 16 + Subsection "Display" + Depth 16 + Modes "1280x1024" "1024x768" "800x600" "640x480" + ViewPort 0 0 + EndSubsection + EndSection + </verb> + <p> + The kernel module for the Voodoo3 is named <tt>tdfx.o</tt> and + should be installed in /lib/modules/KERNEL-VERSION/misc/. + It will be automatically loaded by the Xserver if needed. + <p> + The DRI 3D driver for the Voodoo3 should be in + <tt>/usr/X11R6/lib/modules/dri/tdfx_dri.so</tt>. + This will be automatically loaded by libGL.so. + <sect2>Troubleshooting <p> <itemize> @@ -539,6 +638,9 @@ bit/pixel screen mode. Use <tt/xdpyinfo/ to verify that all your visuals are depth 16. Edit your XF86Config file if needed. + <item> + The <tt>/dev/3dfx</tt> device is not used for DRI; it's only for + Glide on older 3dfx hardware. </itemize> <sect2>Performance @@ -565,6 +667,9 @@ <p> <itemize> <item> + Glide cannot be used directly; only OpenGL-based programs are + supported on the Voodoo3. + <item> SSystem has problems because of poorly set near and far clipping planes. The office.unc Performer model also suffers from this problem. @@ -573,10 +678,120 @@ <sect1>Intel i810 <p> + Information to be added in the future. + <sect1>Matrox G400 <p> + <sect2>Configuration +<p> + Your XF86Config file's device section must specify the + <tt>mga</tt> device: + <verb> + Section "Device" + Identifier "G400" + VendorName "Matrox" + Driver "mga" + EndSection + </verb> + The Screen section should then reference the G400 mga device: + <verb> + Section "Screen" + Identifier "Screen 1" + Device "G400" + Monitor "High Res Monitor" + DefaultDepth 16 + Subsection "Display" + Depth 16 + Modes "1280x1024" "1024x768" "800x600" "640x480" + ViewPort 0 0 + EndSubsection + EndSection + </verb> + <p> + The kernel module for the G400 is named <tt>mga.o</tt> and + should be installed in /lib/modules/KERNEL-VERSION/misc/. + It will be automatically loaded by the Xserver if needed. + <p> + The DRI 3D driver for the G400 should be in + <tt>/usr/X11R6/lib/modules/dri/mga_dri.so</tt>. + This will be automatically loaded by libGL.so. + + <sect2>Troubleshooting +<p> + <itemize> + <item> + 3D acceleration for the G400 is only supported in the 16 + bit/pixel screen mode at this time. 32bpp will be supported + in the future. + Use <tt/xdpyinfo/ to verify that all your visuals are depth 16. + Edit your XF86Config file if needed. + </itemize> + + <sect2>Performance +<p> + No data at this time. + + <sect2>Known Problems +<p> + No data at this time. + + <sect1>ATI Rage 128 <p> + <sect2>Configuration +<p> + Your XF86Config file's device section must specify the + <tt>r128</tt> device: + <verb> + Section "Device" + Identifier "Rage128" + VendorName "ATI" + Driver "r128" + EndSection + </verb> + The Screen section should then reference the Rage 128 device: + <verb> + Section "Screen" + Identifier "Screen 1" + Device "Rage128" + Monitor "High Res Monitor" + DefaultDepth 16 + Subsection "Display" + Depth 16 + Modes "1280x1024" "1024x768" "800x600" "640x480" + ViewPort 0 0 + EndSubsection + Subsection "Display" + Depth 32 + Modes "1280x1024" "1024x768" "800x600" "640x480" + ViewPort 0 0 + EndSubsection + EndSection + </verb> + <p> + The kernel module for the Rage 128 is named <tt>r128.o</tt> and + should be installed in /lib/modules/KERNEL-VERSION/misc/. + It will be automatically loaded by the Xserver if needed. + <p> + The DRI 3D driver for the Rage 128 should be in + <tt>/usr/X11R6/lib/modules/dri/r128_dri.so</tt>. + This will be automatically loaded by libGL.so. + <p> + You may also set your screen depth to 32 for 32bpp mode. + <p> + + <sect2>Performance +<p> + While PCI Rage 128 based cards are supported, they do not yet + support PCI GART, so they will not perform as well as their + AGP counterparts. + + <sect2>Known Problems +<p> + DGA is not yet supported in the ATI Rage 128 X server. This + feature will be added in a future release. + + <sect1>3DLabs Oxygen GMX 2000 <p> The driver for this hardware was experimental and is no longer being @@ -621,6 +836,50 @@ which will be addressed in the future. + <sect1>libGL.so and dlopen() +<p> + A number of popular OpenGL applications on Linux (such as Quake3, + HereticII, Heavy Gear 2, etc) dynamically open the libGL.so + library at runtime with dlopen(), rather than linking with -lGL + at compile/link time. +<p> + If dynamic loading of libGL.so is not implemented carefully, there + can be a number of serious problems. + Here are the things to be careful of in your application: + <itemize> + <item>Specify the RTLD_GLOBAL flag to dlopen(). + If you don't do this then you'll likely see a runtime error message + complaining that _glapi_Context is undefined when libGL.so + tries to open a hardware-specific driver. + Without this flag, <em>nested</em> opening of dynamic libraries + does not work. + <item>Do not close the library with dlclose() until after + XCloseDisplay() has been called. + When libGL.so initializes itself it registers several callbacks + functions with Xlib. + When XCloseDisplay() is called those callback functions are + called. + If libGL.so has already been unloaded with dlclose() this will + cause a segmentation fault. + <item> + Your application should link with -lpthread. + On Linux, libGL.so uses the pthreads library in order to provide + thread safety. + There is apparently a bug in the dlopen()/dlclose() code which + causes crashes if the library uses pthreads but the parent + application doesn't. + The only known work-around is to link the application with + -lpthread. + </itemize> + + Some applications don't yet incorporate these procedures and + may fail. + For example, changing the graphics settings in some video games + will expose this problem. + The DRI developers are working with game vendors to prevent this + problem in the future. + + <sect1>Bug Database <p> The DRI bug database which includes bugs related to specific @@ -654,6 +913,9 @@ <item>Visit the <htmlurl url="http://dri.sourceforge.net" name="DRI project on SourceForge.net"> for the latest development news about the DRI and 3D drivers. + <item>The <htmlurl url="http://dri.sourceforge.net/DRIcompile.html" + name="DRI Compilation Guide"> explains how to download, compile + and install the DRI for yourself. </itemize> <sect1>Support @@ -664,54 +926,13 @@ <htmlurl url="http://sourceforge.net/mail/?group_id=387" name="SourceForge"> is a forum for people to discuss DRI problems. <item> - XXX IHV support? - <item> - XXX Linux distro support? + In the future there may be IHV and Linux vendor support resources + for the DRI. </itemize> </article> -<!-- -1. Introduction -2. Supported Hardware -3. Prerequisite Software -4. Start-Up -5. Using 3D Acceleration - 5.1 libGL.so - 5.2 glxinfo - 5.3 Environment variables -6. General Trouble Shooting -7. Hardware-Specific Information - 7.1 3dfx - 7.2 Intel i810 - 7.3 Matrox G400 - 7.4 ATI Rage 128 - 7.5 3DLabs Gamma -8. Limitation and Known Bugs - 8.1 OpenGL - 8.2 GLX - 8.3 Signal Handling - 8.4 Scheduling - 8.5 Bug Database -9. Resources - 9.1 Software Resources - GLU - GLUT - Glide3 - Utilities and demos - Sample XF86Config files - 9.2 Documentation - www.XFree86.org - www.opengl.org - www.linux.com - www.precisioninsight.com - sourceforge.net - 9.3 Support - IHVs - RedHat - --> - <!-- Local Variables: --> <!-- fill-column: 72 --> <!-- End: --> diff --git a/xc/programs/Xserver/hw/xfree86/doc/sgml/DRIcomp.sgml b/xc/programs/Xserver/hw/xfree86/doc/sgml/DRIcomp.sgml new file mode 100644 index 000000000..eeda0e057 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/doc/sgml/DRIcomp.sgml @@ -0,0 +1,501 @@ +<!doctype linuxdoc system> +<!-- Created: Sun Mar 12 13:00:00 2000 by brian@precisioninsight.com --> +<!-- Revised: Fri May 19 09:36:02 2000 by martin@valinux.com --> +<!-- $Id: DRIcomp.sgml,v 1.6.12.1 2000/05/30 14:47:49 dfr Exp $ --> + + <article> + + <title>DRI Compilation Guide + <author> + <htmlurl url="http://www.precisioninsight.com/" + name="Precision Insight, Inc."> + <date>18 May 2000 + + <ident> + $XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/DRI.sgml,v 1.3 2000/04/05 05:38:41 brianp Exp $ + </ident> + + <toc> + + <sect>Preamble + + <sect1>Copyright + <p> + <bf>Copyright © 2000 by Precision Insight, Inc., + Cedar Park, Texas. + All Rights Reserved.</bf> + <p> + <bf>Permission is granted to make and distribute verbatim copies + of this document provided the copyright notice and this permission + notice are preserved on all copies.</bf> + + <sect1>Trademarks + <p> + OpenGL is a registered trademark and SGI is a trademark of + Silicon Graphics, Inc. + Unix is a registered trademark of The Open Group. + The `X' device and X Window System are trademarks of The Open Group. + XFree86 is a trademark of The XFree86 Project. + Linux is a registered trademark of Linus Torvalds. + Intel is a registered trademark of Intel Corporation. + 3Dlabs, GLINT, and Oxygen are either registered trademarks or + trademarks of 3Dlabs Inc. Ltd. + 3dfx, Voodoo3, Voodoo4, and Voodoo5 are registered trademarks of + 3dfx Interactive, Incorporated. + Matrox is a registered trademark of Matrox Electronic Systems Ltd. + ATI Rage is a registered trademark of ATI Technologies, Inc. + All other trademarks mentioned are the property of their + respective owners. + + + <sect>Introduction + <p> + This document describes how to download, compile and install the + DRI project. + This information is intended for experienced Linux developers. + Beginners are probably better off installing precompiled packages. + <p> + Edits, corrections and updates to this document may be mailed + to brian@precisioninsight.com. + + + <sect>Prerequisites + <p> + You'll need the following: + <itemize> + <item>At least 400MB of free disk space. More is needed if you want + to build with debugging information or keep several build trees. + <item>A fast system. Using a PIII-550 it takes about 1/2 hour to + build everthing. + <item>GCC compiler and related tools. + <item>ssh (secure shell) for registed developer downloading of the + DRI source tree + </itemize> + + <p> + For 3dfx Voodoo3 hardware, you'll also need: + <itemize> + <item>Glide3x headers and runtime library if you want to use the + 3dfx driver. + These can be obtained from + <htmlurl url="http://linux.3dfx.com/open_source/glide_kit.htm" + name="linux.3dfx.com">. + <item>Linux kernel 2.2.x. + The DRI developers have been using stock RedHat 6.1 systems + (kernel 2.2.12-20). + Later kernel versions will be supported in the future. + </itemize> + + <p> + For Matrox G400 hardware, you'll also need: + <itemize> + <item>Linux kernel 2.3.51. Other kernel versions may work but + this one is known to work. + </itemize> + + <p> + For ATI Rage hardware, you'll also need: + <itemize> + <item>Linux kernel 2.3.51. Other kernel versions may work but + this one is known to work. + </itemize> + + + <sect>Kernel preparation + <p> + You may have to upgrade your Linux kernel in order to use the DRI. + This is because you need a kernel version which supports AGP. + Building a new Linux kernel can be difficult for beginners but + there are resouces on the Internet to help. + This document assumes experience with configuring, building and + installing Linux kernels. + <p> + Linux kernels can be downloaded from + <htmlurl url="http://www.kernel.org/pub/linux/kernel/" + name="www.kernel.org"> + <p> + Download the needed kernel and put it in /usr/src. + Create a directory for the source and unpack it. + For example: + <verb> + cd /usr/src + rm -f linux + mkdir linux-2.3.51 + ln -s linux-2.3.51 linux + bzcat linux-2.3.51.tar.bz2 | tar xf - + </verb> + <p> + Now configure your kernel. + You might, for example, use <tt>make menuconfig</tt> and do the + following: + + <itemize> + <item>Go to <em>Code maturity level options</em> + <item>Enable <em>Prompt for development and/or incomplete + code/drivers</em> + <item>hit ESC + <item>Go to <em>Character devices</em> + <item>Disable <em>Direct Rendering Manager (XFree86 DRI support)</em> + since we'll use the DRI module from the XFree86/DRI tree. + <item>Go to <em>/dev/agpgart (AGP Support) (EXPERIMENTAL) (NEW)</em> + <item>Hit SPACE twice + <item>Enable all chipsets' support for AGP + </itemize> + + <p>It's recommended that you turn on MTRRs under <em>Processor type + and Features</em>, but not required. + + <p> + Configure the rest of the kernel as required for your system + (i.e. ethernet, scsi, etc) + <p> + Exit, saving your kernel configuration. + <p> + Edit your /etc/lilo.conf file. + Make sure you have an image entry as follows (or similar): + <verb> + image=/boot/vmlinuz + label=linux.2.3.51 + read-only + root=/dev/hda1 + </verb> + <p> + The important part is that you have /boot/vmlinuz without a + trailing version number. + If this is the first entry in your /etc/lilo.conf AND you + haven't set a default, then this will be your default kernel. + + <p> + Now compile the new kernel: + + <verb> + cd /usr/src/linux-2.3.51 + make dep ; make bzImage + make modules ; make modules_install + make install + </verb> + Note that the final part, make install, will automatically run + lilo for you. + <p> + Now reboot to use this new kernel. + + + <sect>Downloading the XFree86/DRI CVS Sources + <p> + The DRI project is hosted by VA Linux Systems' + <htmlurl url="http://sourceforge.net/project/?group_id=387" + name="SourceForge">. + The DRI source code, which is a subset of the XFree86 source tree, + is kept in a CVS repository there. + <p> + The DRI CVS sources may be accessed either anonymously or as a + registered SourceForge user. + It's recommended that you become a registered SourceForge user so + that you may submit non-annonymous bug reports and can participate + in the mailing lists. + + <sect1>Anonymous CVS download: + <p> + <enum> + <item>Create a directory to store the CVS files: + <p> + <verb> + cd ~ + mkdir DRI-CVS + </verb> + You could put your CVS directory in a different place but we'll + use <tt>~/DRI-CVS/</tt> here. + <p> + <item>Check out the CVS sources: + <p> + <verb> + cd ~/DRI-CVS + cvs -d:pserver:anonymous@cvs.dri.sourceforge.net:/cvsroot/dri login + (hit ENTER when prompted for a password) + cvs -z3 -d:pserver:anonymous@cvs.dri.sourceforge.net:/cvsroot/dri co xc + </verb> + <p> + The -z3 flag causes compression to be used in order to reduce + the download time. + </enum> + + + <sect1>Registered CVS download: + <p> + <enum> + <item>Create a directory to store the CVS files: + <p> + <verb> + cd ~ + mkdir DRI-CVS + </verb> + You could put your CVS directory in a different place but we'll + use <tt>~/DRI-CVS/</tt> here. + <p> + <item>Set the CVS_RSH environment variable: + <p> + <verb> + setenv CVS_RSH ssh // if using csh or tcsh + export CVS_RSH=ssh // if using sh or bash + </verb> + <item>Check out the CVS sources: + <p> + <verb> + cd ~/DRI-CVS + cvs -z3 -dYOURID@cvs.dri.sourceforge.net:/cvsroot/dri co xc + </verb> + Replace <tt>YOURID</tt> with your CVS login name. + You'll be prompted to enter your sourceforge password. + <p> + The -z3 flag causes compression to be used in order to reduce + the download time. + </enum> + + + <sect>Updating your CVS sources + <p> + In the future you'll want to occasionally update your local copy of + the DRI source code to get the latest changes. + This can be done with: + <verb> + cd ~/DRI-CVS + cvs -z3 update -dA xc + </verb> + The -d flag causes any new subdirectories to be created and -A causes + most recent trunc sources to be fetched, not branch sources. + + + <sect>Compiling the XFree86/DRI tree + <sect1>Make a build tree + <p> + Rather than placing object files and library files right in the + source tree, they're instead put into a parallel <em>build</em> tree. + The build tree is made with the <tt>lndir</tt> command: + <verb> + cd ~/DRI-CVS + ln -s xc XFree40 + mkdir build + cd build + lndir -silent -ignorelinks ../XFree40 + </verb> + <p> + The build tree will be populated with symbolic links which point + back into the CVS source tree. + <p> + Advanced users may have several build trees for compiling and + testing with different options. + + <sect1>Edit the host.def file + <p> + The <tt>~/DRI-CVS/build/xc/config/cf/host.def</tt> file is used + to configure the XFree86 build process. + You can change it to customize your build options or make adjustments + for your particular system configuration + <p> + The default <tt>host.def</tt> file will look something like this: + <verb> + #define DefaultCCOptions -Wall + #define DefaultGcc2i386Opt -O2 + #define LibraryCDebugFlags -O2 + #define BuildServersOnly YES + #define XF86CardDrivers vga tdfx mga r128 + #define LinuxDistribution LinuxRedHat + #define DefaultCCOptions -ansi GccWarningOptions -pipe + #define BuildXF86DRI YES + #define HasGlide3 YES + /* Optionally turn these on for debugging */ + /* #define GlxBuiltInTdfx YES */ + /* #define GlxBuiltInMga YES */ + /* #define GlxBuiltInR128 YES */ + /* #define DoLoadableServer NO */ + #define SharedLibFont NO + </verb> + The <tt>ProjectRoot</tt> variable specifies where the XFree86 files + will be installed. + You probably don't want to use <tt>/usr/X11R6/</tt> because that + would overwrite your default X files. + The following is recommended: + <verb> + #define ProjectRoot /usr/XF86-main + </verb> + <p> + Especially note the <em>XF86CardDrivers</em> line to be sure your + driver is listed. + <p> + If you have 3dfx hardware be sure that the Glide 3x headers are + installed in <tt>/usr/include/glide3/</tt> and that the Glide 3x + library is installed at <tt>/usr/lib/libglide3x.so</tt>. + <p> + If you do not have 3dfx hardware comment out the <tt>HasGlide3</tt> + line in <tt>host.def</tt>. + <p> + + <sect1>Compile + <p> + To compile the complete DRI tree: + <verb> + cd ~/DRI-CVS/build/xc/ + make World >& World.LOG + </verb> + Or if you want to watch the compilation progress: + <verb> + cd ~/DRI-CVS/build/xc/ + make World >& World.LOG & + tail -f World.LOG + </verb> + With the default compilation flags it's normal to get a lot of + warnings during compilation. + <p> + Building will take some time so you may want to go check your + email or visit slashdot. + + <sect1>Check for compilation errors + <p> + Using your text editor, examine <tt>World.LOG</tt> for errors + by searching for the pattern <tt>***</tt>. + <p> + Verify that the DRI kernel module(s) for your system were built: + <verb> + cd ~/DRI-CVS/build/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel + ls + </verb> + <p> + For the 3dfx Voodoo, you should see <em>tdfx.o</em>. + For the Matrox G400, you should see <em>mga.o</em>. + For the ATI Rage 128, you should see <em>r128.o</em>. + <p> + If the DRI kernel module(s) failed to build you should verify + that you're using the right version of the Linux kernel. + The most recent kernels are not always supported. + <p> + If your build machine is running a different version of the kernel + than your target machine (i.e. 2.2.12-20 vs. 2.3.99-pre6), make will + select the wrong kernel headers. This can be fixed by explicitly + setting the value of <tt>TREE</tt>. + If the path to your kernel source is + <tt>/bigdisk/linux-2.3.99-pre6</tt>, + <verb> + cd ~/DRI-CVS/build/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel + make TREE=/bigdisk/linux-2.3.99-pre6 + </verb> + or alternatively, edit Makefile to include this change. + <p> + After fixing the errors, do <tt>make World</tt> again. + Later, you might just compile parts of the source tree but it's + important that the whole tree will build first. + + + <sect>Installing + <p> + After the DRI tree has been compiled you can install the XFree86 + headers, libraries, programs, etc for testing. + + <sect1>X Installation + <p> + As mentioned above, the install directory is specified by the + <tt>ProjectRoot</tt> variable in the <tt>host.def</tt> file. + Create that directory now if it doesn't already exist: + <verb> + mkdir /usr/XF86-main + </verb> + <p> + You'll have to change to root since the install process puts + several files in <tt>/etc/X11/</tt> and sets the setuid flag on + the X server executable. + <verb> + cd ~/DRI-CVS/build/xc + su + make install + </verb> + Edit your <tt>/etc/ld.so.conf</tt> file and put + <tt>/usr/XF86-main/lib</tt> as the first line. + Continue with: + <verb> + ldconfig + exit + </verb> + <p> + Look in <tt>/usr/XF86-main</tt> to be sure the files installed + there. + <P> + Strictly speaking, installing the DRI tree isn't required. + It's possible to run and test the X server directly from the + build directory but it's a bit error prone. + + <sect1>Update Locale Information + <p> + To update your X locale information do the following: + <verb> + cd ~/DRI-CVS/build/xc/nls + xmkmf + make + make install + </verb> + This will prevent a locale error message from being printed + when you run Xlib programs. + + <sect>X Server Configuration + <p> + If your X server is currently running you'll have to stop it + and return to a virtual terminal. + <p> + First, setup your XF86Config file. + It should load the GLX and DRI modules and specify the driver to + use for your hardware. + See the <htmlurl url="http://dri.sourceforge.net/DRIuserguide.html" + name="DRI User Guide"> for detailed information. + <p> + You may want to make a backup copy of your existing + <tt>/etc/X11/XF86Config</tt> file first. + <p> + It's very important that you set the <tt>ModulePath</tt> option to + point to your installation directory: + <verb> + ModulePath "/usr/XF86-main/lib/modules" + </verb> + <p> + Double check with this: + <verb> + grep ModulePath /etc/X11/XF86Config + </verb> + <p> + Next, your <tt>~/.xinitrc</tt> file controls which clients will be + launched when your X server starts. + You might put the following in yours: + <verb> + xset b off + xsetroot -solid "#004070" + xmodmap -e "clear mod4" + xrdb -merge ~/.Xdefaults + xterm -geometry +0+0 & + xterm -geometry +512+0 & + fvwm + </verb> + <p> + + <sect>X Server Start-up + <p> + The X server can be started with: + <p> + <verb> + xinit -- /usr/XF86-main/bin/XFree86 + </verb> + <p> + Automatic loading of DRM kernel modules was added to the X server + in XFree86 4.0.1. + This feature, and manual loading of kernel modules, is documented + in the DRI user guide. + <p> + At this point your X server should be up and running with + hardware-accelerated direct rendering. + Please read the + <htmlurl url="http://dri.sourceforge.net/DRIuserguide.html" + name="DRI User Guide"> for trouble shooting information. + + + </article> + + + <!-- Local Variables: --> + <!-- fill-column: 72 --> + <!-- End: --> diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile b/xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile index 331396f38..9e167d6c7 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile @@ -6,13 +6,9 @@ XCOMM #define IHaveModules #include <Server.tmpl> -# -# Uncomment these to build with DRI support when available -# -#undef BuildXF86DRI #if BuildXF86DRI -DRISRCS = i810_dri.c i810_drm.c -DRIOBJS = i810_dri.o i810_drm.o +DRISRCS = i810_dri.c +DRIOBJS = i810_dri.o DRIINCLUDES = -I$(SERVERSRC)/GL/dri -I$(LIBSRC)/GL/dri \ -I$(XF86OSSRC)/linux/drm/kernel DRIDEFINES = $(GLX_DEFINES) @@ -63,7 +59,6 @@ InstallDriverSDKNonExecFile(i810_cursor.c,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_driver.c,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_dri.c,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_dri.h,$(DRIVERSDKDIR)/drivers/i810) -InstallDriverSDKNonExecFile(i810_dripriv.h,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_io.c,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_memory.c,$(DRIVERSDKDIR)/drivers/i810) InstallDriverSDKNonExecFile(i810_wmark.c,$(DRIVERSDKDIR)/drivers/i810) diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810.h b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810.h index 6aceea540..58a17ad74 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810.h @@ -36,16 +36,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef _I810_H_ #define _I810_H_ - +#include "compiler.h" #include "xf86PciInfo.h" #include "xf86Pci.h" #include "i810_reg.h" #include "xaa.h" #include "xf86Cursor.h" -#undef XF86DRI - - #ifdef XF86DRI #include "xf86drm.h" #include "sarea.h" @@ -211,8 +208,8 @@ typedef struct _I810Rec { extern Bool I810DRIScreenInit(ScreenPtr pScreen); extern void I810DRICloseScreen(ScreenPtr pScreen); extern Bool I810DRIFinishScreenInit(ScreenPtr pScreen); -extern Bool I810drmInitDma(ScrnInfoPtr pScrn); -extern Bool I810drmCleanupDma(ScrnInfoPtr pScrn); +extern Bool I810InitDma(ScrnInfoPtr pScrn); +extern Bool I810CleanupDma(ScrnInfoPtr pScrn); #define I810PTR(p) ((I810Ptr)((p)->driverPrivate)) #define I810REGPTR(p) (&(I810PTR(p)->ModeReg)) @@ -312,7 +309,7 @@ extern void I810EmitInvarientState(ScrnInfoPtr pScrn); /* To remove all debugging, make sure I810_DEBUG is defined as a * preprocessor symbol, and equal to zero. */ -#define I810_DEBUG 0 +#define I810_DEBUG 0 #ifndef I810_DEBUG #warning "Debugging enabled - expect reduced performance" extern int I810_DEBUG; diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c index 0f67180d2..1a410bcd1 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c @@ -271,6 +271,7 @@ I810WaitLpRing( ScrnInfoPtr pScrn, int n, int timeout_millis ) DRICloseScreen(screenInfo.screens[pScrn->scrnIndex]); } #endif + pI810->AccelInfoRec = NULL; /* Stops recursive behavior */ FatalError("lockup\n"); } @@ -301,13 +302,9 @@ I810Sync( ScrnInfoPtr pScrn ) #ifdef XF86DRI /* VT switching tries to do this. */ - if (!pI810->LockHeld) { + if (!pI810->LockHeld && pI810->directRenderingEnabled) { return; } - - -/* if (pI810->directRenderingEnabled) */ -/* DRIUnlockLockQueiscent( pScrn->pScreen ); */ #endif /* Send a flush instruction and then wait till the ring is empty. @@ -635,19 +632,19 @@ I810RefreshRing(ScrnInfoPtr pScrn) } - +/* Emit on gaining VT? + */ void I810EmitInvarientState(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); - BEGIN_LP_RING( 8 ); + BEGIN_LP_RING( 10 ); OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); OUT_RING( GFX_CMD_CONTEXT_SEL | CS_UPDATE_USE | CS_USE_CTX0 ); OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); OUT_RING( 0 ); - OUT_RING( GFX_OP_COLOR_CHROMA_KEY ); OUT_RING( CC1_UPDATE_KILL_WRITE | CC1_DISABLE_KILL_WRITE | @@ -658,5 +655,8 @@ I810EmitInvarientState(ScrnInfoPtr pScrn) OUT_RING( 0 ); OUT_RING( 0 ); +/* OUT_RING( CMD_OP_Z_BUFFER_INFO ); */ +/* OUT_RING( pI810->DepthBuffer.Start | pI810->auxPitchBits); */ + ADVANCE_LP_RING(); } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c index c63f9ed20..591207b65 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c @@ -1,4 +1,4 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c,v 1.2 2000/03/02 16:07:49 martin Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c,v 1.3 1999/09/27 06:29:57 dawes Exp $ */ #include "xf86.h" #include "xf86_OSproc.h" @@ -20,10 +20,6 @@ #include "i810.h" #include "i810_dri.h" -#include "xf86drm.h" -#include "dristruct.h" - - static char I810KernelDriverName[] = "i810"; static char I810ClientDriverName[] = "i810"; @@ -62,6 +58,43 @@ static int i810_pitch_flags[] = { 0 }; +Bool I810CleanupDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + Bool ret_val; + + ret_val = drmI810CleanupDma(pI810->drmSubFD); + if(ret_val == FALSE) ErrorF("I810 Dma Cleanup Failed\n"); + return ret_val; +} + +Bool I810InitDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RingBuffer *ring = &(pI810->LpRing); + drmI810Init info; + Bool ret_val; + + info.start = ring->mem.Start; + info.end = ring->mem.End; + info.size = ring->mem.Size; + info.ring_map_idx = 6; + info.buffer_map_idx = 5; + info.sarea_off = sizeof(XF86DRISAREARec); + + info.front_offset = 0; + info.back_offset = pI810->BackBuffer.Start; + info.depth_offset = pI810->DepthBuffer.Start; + info.w = pScrn->virtualX; + info.h = pScrn->virtualY; + info.pitch = pI810->auxPitch; + info.pitch_bits = pI810->auxPitchBits; + + ret_val = drmI810InitDma(pI810->drmSubFD, &info); + if(ret_val == FALSE) ErrorF("I810 Dma Initialization Failed\n"); + return ret_val; +} + static Bool I810InitVisualConfigs(ScreenPtr pScreen) { @@ -260,8 +293,13 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) int width = pScrn->displayWidth * pI810->cpp; int i; - /* ToDo : save agpHandles? */ - +#if XFree86LOADER + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. */ + if (!LoaderSymbol("GlxSetVisualConfigs")) return FALSE; + if (!LoaderSymbol("DRIScreenInit")) return FALSE; + if (!LoaderSymbol("drmAvailable")) return FALSE; +#endif pDRIInfo = DRICreateInfoRec(); if (!pDRIInfo) { @@ -279,10 +317,12 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) pDRIInfo->drmDriverName = I810KernelDriverName; pDRIInfo->clientDriverName = I810ClientDriverName; pDRIInfo->busIdString = xalloc(64); + sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d", ((pciConfigPtr)pI810->PciInfo->thisCard)->busnum, ((pciConfigPtr)pI810->PciInfo->thisCard)->devnum, ((pciConfigPtr)pI810->PciInfo->thisCard)->funcnum); + pDRIInfo->ddxDriverMajorVersion = 0; pDRIInfo->ddxDriverMinorVersion = 1; pDRIInfo->ddxDriverPatchVersion = 0; @@ -302,7 +342,7 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) /* For now the mapping works by using a fixed size defined * in the SAREA header */ - if (sizeof(XF86DRISAREARec)+sizeof(drm_i810_sarea_t)>SAREA_MAX) { + if (sizeof(XF86DRISAREARec)+sizeof(I810SAREARec)>SAREA_MAX) { ErrorF("Data does not fit in SAREA\n"); return FALSE; } @@ -378,9 +418,9 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) * under the DRI. */ - dcacheHandle = drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL); + drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL, &dcacheHandle); pI810->dcacheHandle = dcacheHandle; - + #define Elements(x) sizeof(x)/sizeof(*x) for (pitch_idx = 0 ; pitch_idx < Elements(i810_pitches) ; pitch_idx++) @@ -392,9 +432,8 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) "Couldn't find depth/back buffer pitch"); DRICloseScreen(pScreen); return FALSE; - } - else { - back_size = i810_pitches[pitch_idx] * pScrn->virtualY; + } else { + back_size = i810_pitches[pitch_idx] * (pScrn->virtualY + 4); back_size = ((back_size + 4096 - 1) / 4096) * 4096; } @@ -411,14 +450,18 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) } else { sysmem_size = sysmem_size - 2*back_size; } - - sysmem_size -= 4096; - if(sysmem_size > ((48*1024*1024) - 1) ) { - sysmem_size = (48*1024*1024) - (2*4096); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "User requested more memory then fits in the agp aperture\n" + + if(sysmem_size > 48*1024*1024) { + sysmem_size = 48*1024*1024; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "User requested more memory then fits in the agp aperture\n" "Truncating to %d bytes of memory\n", sysmem_size); } + + sysmem_size -= 4096; /* remove 4k for the hw cursor */ + pI810->SysMem.Start = 0; pI810->SysMem.Size = sysmem_size; pI810->SysMem.End = sysmem_size; @@ -428,7 +471,6 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) if (dcacheHandle != 0) { /* The Z buffer is always aligned to the 48 mb mark in the aperture */ - if(drmAgpBind(pI810->drmSubFD, dcacheHandle, 48*1024*1024) == 0) { xf86memset (&pI810->DcacheMem, 0, sizeof(I810MemRange)); xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -454,7 +496,7 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: no dcache memory found\n"); } - agpHandle = drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL); + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, &agpHandle); pI810->backHandle = agpHandle; if(agpHandle != 0) { @@ -481,8 +523,8 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) if(dcacheHandle == 0) { /* The Z buffer is always aligned to the 48 mb mark in the aperture */ - agpHandle = drmAgpAlloc(pI810->drmSubFD, back_size, 0, - NULL); + drmAgpAlloc(pI810->drmSubFD, back_size, 0, + NULL, &agpHandle); pI810->zHandle = agpHandle; if(agpHandle != 0) { @@ -509,8 +551,7 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) /* Now allocate and bind the agp space. This memory will include the * regular framebuffer as well as texture memory. */ - - agpHandle = drmAgpAlloc(pI810->drmSubFD, sysmem_size, 0, NULL); + drmAgpAlloc(pI810->drmSubFD, sysmem_size, 0, NULL, &agpHandle); if(agpHandle == 0) { ErrorF("drmAgpAlloc failed\n"); DRICloseScreen(pScreen); @@ -524,8 +565,8 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) return FALSE; } - agpHandle = drmAgpAlloc(pI810->drmSubFD, 4096, 2, - (unsigned long *)&pI810->CursorPhysical); + drmAgpAlloc(pI810->drmSubFD, 4096, 2, + (unsigned long *)&pI810->CursorPhysical, &agpHandle); pI810->cursorHandle = agpHandle; if (agpHandle != 0) { @@ -545,7 +586,6 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) pI810->CursorPhysical = 0; } - I810SetTiledMemory(pScrn, 1, pI810->DepthBuffer.Start, i810_pitches[pitch_idx], @@ -558,10 +598,9 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) pI810->auxPitch = i810_pitches[pitch_idx]; pI810->auxPitchBits = i810_pitch_flags[pitch_idx]; - pI810->SavedDcacheMem = pI810->DcacheMem; - pI810DRI->backbufferSize = pI810->BackBuffer.Size; + if (drmAddMap(pI810->drmSubFD, (drmHandle)pI810->BackBuffer.Start, pI810->BackBuffer.Size, DRM_AGP, 0, &pI810DRI->backbuffer) < 0) { @@ -586,6 +625,13 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) I810AllocHigh( &(pI810->BufferMem), &(pI810->SysMem), I810_DMA_BUF_NR * I810_DMA_BUF_SZ); + if(pI810->BufferMem.Start == 0 || + pI810->BufferMem.End - pI810->BufferMem.Start > + I810_DMA_BUF_NR * I810_DMA_BUF_SZ) { + ErrorF("Not enough memory for dma buffers\n"); + DRICloseScreen(pScreen); + return FALSE; + } if(drmAddMap(pI810->drmSubFD, (drmHandle)pI810->BufferMem.Start, pI810->BufferMem.Size, DRM_AGP, 0, &pI810->buffer_map) < 0) { @@ -608,7 +654,6 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) /* Use the rest of memory for textures. */ pI810DRI->textureSize = pI810->SysMem.Size; - i = mylog2(pI810DRI->textureSize / I810_NR_TEX_REGIONS); if (i < I810_LOG_MIN_TEX_REGION_SIZE) @@ -617,15 +662,14 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) pI810DRI->logTextureGranularity = i; pI810DRI->textureSize = (pI810DRI->textureSize >> i) << i; /* truncate */ - if(pI810DRI->textureSize < 512*1024) { ErrorF("Less then 512k for textures\n"); DRICloseScreen(pScreen); + return FALSE; } I810AllocLow( &(pI810->TexMem), &(pI810->SysMem), pI810DRI->textureSize); - if (drmAddMap(pI810->drmSubFD, (drmHandle)pI810->TexMem.Start, pI810->TexMem.Size, DRM_AGP, 0, @@ -650,7 +694,7 @@ Bool I810DRIScreenInit(ScreenPtr pScreen) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] added %d %d byte DMA buffers\n", bufs, I810_DMA_BUF_SZ); - I810drmInitDma(pScrn); + I810InitDma(pScrn); /* Okay now initialize the dma engine */ @@ -718,7 +762,7 @@ I810DRICloseScreen(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I810Ptr pI810 = I810PTR(pScrn); - I810drmCleanupDma(pScrn); + I810CleanupDma(pScrn); if(pI810->dcacheHandle) drmAgpFree(pI810->drmSubFD, pI810->dcacheHandle); if(pI810->backHandle) drmAgpFree(pI810->drmSubFD, pI810->backHandle); @@ -768,7 +812,7 @@ I810DestroyContext(ScreenPtr pScreen, drmContext hwContext, Bool I810DRIFinishScreenInit(ScreenPtr pScreen) { - drm_i810_sarea_t *sPriv = (drm_i810_sarea_t *)DRIGetSAREAPrivate(pScreen); + I810SAREARec *sPriv = (I810SAREARec *)DRIGetSAREAPrivate(pScreen); xf86memset( sPriv, 0, sizeof(sPriv) ); return DRIFinishScreenInit(pScreen); } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c index e489d17c9..99369f50b 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c @@ -207,31 +207,19 @@ static const char *ramdacSymbols[] = { #ifdef XF86DRI static const char *drmSymbols[] = { + "drmAvailable", "drmAddBufs", "drmAddMap", - "drmAvailable", - "drmCtlAddCommand", "drmCtlInstHandler", "drmGetInterruptFromBusID", - "drmMapBufs", - "drmMarkBufs", - "drmUnmapBufs", "drmAgpAcquire", "drmAgpRelease", "drmAgpEnable", "drmAgpAlloc", "drmAgpFree", "drmAgpBind", - "drmAgpUnbind", - "drmAgpVersionMajor", - "drmAgpVersionMinor", - "drmAgpGetMode", - "drmAgpBase", - "drmAgpSize", - "drmAgpMemoryUsed", - "drmAgpMemoryAvail", - "drmAgpVendorId", - "drmAgpDeviceId", + "drmI810CleanupDma", + "drmI810InitDma", NULL }; @@ -1047,7 +1035,6 @@ DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); - if (I810_DEBUG&DEBUG_VERBOSE_VGA) { ErrorF("Setting mode in I810Restore:\n"); i810PrintMode( vgaReg, i810Reg ); @@ -1113,7 +1100,7 @@ DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, temp &= ~INTERLACE_ENABLE; temp |= i810Reg->InterlaceControl; hwp->writeCrtc(hwp, INTERLACE_CNTL, temp); - + temp=pI810->readControl(pI810, GRX, ADDRESS_MAPPING); temp &= 0xE0; /* Save reserved bits 7:5 */ temp |= i810Reg->AddressMapping; @@ -1553,7 +1540,6 @@ I810AllocateFront(ScrnInfoPtr pScrn) { xf86memset( &(pI810->LpRing), 0, sizeof( I810RingBuffer ) ); if(I810AllocLow( &(pI810->LpRing.mem), &(pI810->SysMem), 16*4096 )) { - if (I810_DEBUG & DEBUG_VERBOSE_MEMORY) ErrorF( "ring buffer at local %lx\n", pI810->LpRing.mem.Start); @@ -1607,6 +1593,7 @@ I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { /* Have to init the DRM earlier than in other drivers to get agp * memory. Wonder if this is going to be a problem... */ + #ifdef XF86DRI /* * Setup DRI after visuals have been established, but before cfbScreenInit @@ -1625,7 +1612,7 @@ I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { return FALSE; I810AllocateFront(pScrn); #endif - + if (!I810MapMem(pScrn)) return FALSE; pScrn->memPhysBase = (int)pI810->FbBase; @@ -1729,6 +1716,7 @@ I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { } } #endif + #ifdef XF86DRI if (!pI810->directRenderingEnabled) { pI810->DoneFrontAlloc = FALSE; @@ -1738,6 +1726,7 @@ I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { } #endif + if (!xf86InitFBManager(pScreen, &(pI810->FbMemBox))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n"); @@ -1762,7 +1751,7 @@ I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { } } -#if XF86DRI +#ifdef XF86DRI if (pI810->LpRing.mem.Start == 0) { pI810->directRenderingEnabled = 0; I810DRICloseScreen(pScreen); @@ -1892,9 +1881,10 @@ I810LeaveVT(int scrnIndex, int flags) { pI810->LockHeld = 1; } #endif - - I810RefreshRing( pScrn ); - I810Sync( pScrn ); + if(pI810->AccelInfoRec != NULL) { + I810RefreshRing( pScrn ); + I810Sync( pScrn ); + } I810Restore(pScrn); vgaHWLock(hwp); } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_memory.c b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_memory.c index 2cedd9682..f499ffa2d 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_memory.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/i810/i810_memory.c @@ -46,7 +46,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i810.h" #include "i810_reg.h" +#ifdef linux #include <linux/agpgart.h> +#endif int I810AllocLow( I810MemRange *result, I810MemRange *pool, int size ) { @@ -83,6 +85,7 @@ extern int xf86errno; int I810AllocateGARTMemory( ScrnInfoPtr pScrn ) { +#ifdef linux struct _agp_info agpinf; struct _agp_bind bind; struct _agp_allocate alloc; @@ -220,18 +223,23 @@ int I810AllocateGARTMemory( ScrnInfoPtr pScrn ) return TRUE; +#else + return FALSE; +#endif } void I810FreeGARTMemory( ScrnInfoPtr pScrn ) { +#ifdef linux I810Ptr pI810 = I810PTR(pScrn); if (pI810->gartfd != -1) { xf86close( pI810->gartfd ); pI810->gartfd = -1; } +#endif } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.c b/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.c index df23db4f6..0f4ba439a 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.c @@ -22,7 +22,7 @@ #include "mga.h" #include "mga_macros.h" #include "mga_dri.h" -#include "mga_dripriv.h" +#include "mga_wrap.h" static char MGAKernelDriverName[] = "mga"; static char MGAClientDriverName[] = "mga"; @@ -51,172 +51,195 @@ extern void Mga32DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index); extern void Mga32DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, RegionPtr prgnSrc, CARD32 index); -static Bool -MGAInitVisualConfigs(ScreenPtr pScreen) +Bool MgaCleanupDma(ScrnInfoPtr pScrn) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - MGAPtr pMGA = MGAPTR(pScrn); - int numConfigs = 0; - __GLXvisualConfig *pConfigs = 0; - MGAConfigPrivPtr pMGAConfigs = 0; - MGAConfigPrivPtr *pMGAConfigPtrs = 0; - int i; + MGAPtr pMGA = MGAPTR(pScrn); + Bool ret_val; + + ret_val = drmMgaCleanupDma(pMGA->drmSubFD); + if(ret_val == FALSE) ErrorF("Mga Dma Cleanup Failed\n"); + + return ret_val; +} - switch (pScrn->bitsPerPixel) { - case 8: - case 24: - case 32: - break; - case 16: - numConfigs = 4; +Bool MgaLockUpdate(ScrnInfoPtr pScrn, drmLockFlags flags) +{ + MGAPtr pMGA = MGAPTR(pScrn); + Bool ret_val; + + ret_val = drmMgaLockUpdate(pMGA->drmSubFD, flags); + if(ret_val == FALSE) ErrorF("LockUpdate failed\n"); + + return ret_val; +} - if (!(pConfigs = (__GLXvisualConfig*)xnfcalloc(sizeof(__GLXvisualConfig), - numConfigs))) { +Bool MgaInitDma(ScrnInfoPtr pScrn, int prim_size) +{ + MGAPtr pMGA = MGAPTR(pScrn); + MGADRIPtr pMGADRI = (MGADRIPtr)pMGA->pDRIInfo->devPrivate; + MGADRIServerPrivatePtr pMGADRIServer = pMGA->DRIServerInfo; + drmMgaInit init; + Bool ret_val; + + memset(&init, 0, sizeof(drmMgaInit)); + init.reserved_map_agpstart = 0; + init.reserved_map_idx = 3; + init.buffer_map_idx = 4; + init.sarea_priv_offset = sizeof(XF86DRISAREARec); + init.primary_size = prim_size; + init.warp_ucode_size = pMGADRIServer->warp_ucode_size; + + switch(pMGA->Chipset) { + case PCI_CHIP_MGAG400: + init.chipset = MGA_CARD_TYPE_G400; + break; + case PCI_CHIP_MGAG200: + init.chipset = MGA_CARD_TYPE_G200; + break; + case PCI_CHIP_MGAG200_PCI: + default: + ErrorF("Direct rendering not supported on this card/chipset\n"); return FALSE; - } - if (!(pMGAConfigs = (MGAConfigPrivPtr)xnfcalloc(sizeof(MGAConfigPrivRec), + } + + init.frontOffset = pMGADRI->frontOffset; + init.backOffset = pMGADRI->backOffset; + init.depthOffset = pMGADRI->depthOffset; + init.textureOffset = pMGADRI->textureOffset; + init.textureSize = pMGADRI->textureSize; + init.agpTextureSize = pMGADRI->agpTextureSize; + init.cpp = pMGADRI->cpp; + init.stride = pMGADRI->frontPitch; + init.mAccess = pMGA->MAccess; + init.sgram = !pMGA->HasSDRAM; + + memcpy(&init.WarpIndex, &pMGADRIServer->WarpIndex, + sizeof(drmMgaWarpIndex) * MGA_MAX_WARP_PIPES); + + ErrorF("Mga Dma Initialization start\n"); + + ret_val = drmMgaInitDma(pMGA->drmSubFD, &init); + if(ret_val == FALSE) ErrorF("Mga Dma Initialization Failed\n"); + else ErrorF("Mga Dma Initialization done\n"); + return ret_val; +} + +static Bool +MGAInitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MGAPtr pMGA = MGAPTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + MGAConfigPrivPtr pMGAConfigs = 0; + MGAConfigPrivPtr *pMGAConfigPtrs = 0; + int i, db, depth, stencil, accum; + + switch (pScrn->bitsPerPixel) { + case 8: + case 24: + case 32: + break; + case 16: + numConfigs = 4; + + if (!(pConfigs = (__GLXvisualConfig*)xnfcalloc(sizeof(__GLXvisualConfig), numConfigs))) { - xfree(pConfigs); - return FALSE; - } - if (!(pMGAConfigPtrs = (MGAConfigPrivPtr*)xnfcalloc(sizeof(MGAConfigPrivPtr), - numConfigs))) { - xfree(pConfigs); - xfree(pMGAConfigs); - return FALSE; - } - for (i=0; i<numConfigs; i++) - pMGAConfigPtrs[i] = &pMGAConfigs[i]; + return FALSE; + } + if (!(pMGAConfigs = (MGAConfigPrivPtr)xnfcalloc(sizeof(MGAConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pMGAConfigPtrs = (MGAConfigPrivPtr*)xnfcalloc(sizeof(MGAConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pMGAConfigs); + return FALSE; + } + for (i=0; i<numConfigs; i++) + pMGAConfigPtrs[i] = &pMGAConfigs[i]; + + i = 0; + depth = 1; + for (accum = 0; accum <= 1; accum++) { + for (stencil = 0; stencil <= 0; stencil++) { /* no stencil for now */ + for (db=0; db<=1; db++) { + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0; + if (accum) { + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) + pConfigs[i].doubleBuffer = TRUE; + else + pConfigs[i].doubleBuffer = FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + if (depth) + pConfigs[i].depthSize = 16; + else + pConfigs[i].depthSize = 0; + if (stencil) + pConfigs[i].stencilSize = 8; + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (stencil) + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + if (i!=numConfigs) { + ErrorF("Incorrect initialization of visuals\n"); + return FALSE; + } + break; + default: + ; /* unexpected bits/pixelx */ + } + pMGA->numVisualConfigs = numConfigs; + pMGA->pVisualConfigs = pConfigs; + pMGA->pVisualConfigsPriv = pMGAConfigs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pMGAConfigPtrs); + return TRUE; +} - /* config 0: db=FALSE, depth=0 - config 1: db=FALSE, depth=16 - config 2: db=TRUE, depth=0; - config 3: db=TRUE, depth=16 - */ - pConfigs[0].vid = -1; - pConfigs[0].class = -1; - pConfigs[0].rgba = TRUE; - pConfigs[0].redSize = 8; - pConfigs[0].greenSize = 8; - pConfigs[0].blueSize = 8; - pConfigs[0].redMask = 0x00FF0000; - pConfigs[0].greenMask = 0x0000FF00; - pConfigs[0].blueMask = 0x000000FF; - pConfigs[0].alphaMask = 0; - pConfigs[0].accumRedSize = 0; - pConfigs[0].accumGreenSize = 0; - pConfigs[0].accumBlueSize = 0; - pConfigs[0].accumAlphaSize = 0; - pConfigs[0].doubleBuffer = FALSE; - pConfigs[0].stereo = FALSE; - pConfigs[0].bufferSize = 16; - pConfigs[0].depthSize = 0; - pConfigs[0].stencilSize = 0; - pConfigs[0].auxBuffers = 0; - pConfigs[0].level = 0; - pConfigs[0].visualRating = 0; - pConfigs[0].transparentPixel = 0; - pConfigs[0].transparentRed = 0; - pConfigs[0].transparentGreen = 0; - pConfigs[0].transparentBlue = 0; - pConfigs[0].transparentAlpha = 0; - pConfigs[0].transparentIndex = 0; - - pConfigs[1].vid = -1; - pConfigs[1].class = -1; - pConfigs[1].rgba = TRUE; - pConfigs[1].redSize = 8; - pConfigs[1].greenSize = 8; - pConfigs[1].blueSize = 8; - pConfigs[1].redMask = 0x00FF0000; - pConfigs[1].greenMask = 0x0000FF00; - pConfigs[1].blueMask = 0x000000FF; - pConfigs[1].alphaMask = 0; - pConfigs[1].accumRedSize = 0; - pConfigs[1].accumGreenSize = 0; - pConfigs[1].accumBlueSize = 0; - pConfigs[1].accumAlphaSize = 0; - pConfigs[1].doubleBuffer = FALSE; - pConfigs[1].stereo = FALSE; - pConfigs[1].bufferSize = 16; - pConfigs[1].depthSize = 16; - pConfigs[1].stencilSize = 0; - pConfigs[1].auxBuffers = 0; - pConfigs[1].level = 0; - pConfigs[1].visualRating = 0; - pConfigs[1].transparentPixel = 0; - pConfigs[1].transparentRed = 0; - pConfigs[1].transparentGreen = 0; - pConfigs[1].transparentBlue = 0; - pConfigs[1].transparentAlpha = 0; - pConfigs[1].transparentIndex = 0; - - pConfigs[2].vid = -1; - pConfigs[2].class = -1; - pConfigs[2].rgba = TRUE; - pConfigs[2].redSize = 8; - pConfigs[2].greenSize = 8; - pConfigs[2].blueSize = 8; - pConfigs[2].redMask = 0x00FF0000; - pConfigs[2].greenMask = 0x0000FF00; - pConfigs[2].blueMask = 0x000000FF; - pConfigs[2].alphaMask = 0; - pConfigs[2].accumRedSize = 0; - pConfigs[2].accumGreenSize = 0; - pConfigs[2].accumBlueSize = 0; - pConfigs[2].accumAlphaSize = 0; - pConfigs[2].doubleBuffer = TRUE; - pConfigs[2].stereo = FALSE; - pConfigs[2].bufferSize = 16; - pConfigs[2].depthSize = 0; - pConfigs[2].stencilSize = 0; - pConfigs[2].auxBuffers = 0; - pConfigs[2].level = 0; - pConfigs[2].visualRating = 0; - pConfigs[2].transparentPixel = 0; - pConfigs[2].transparentRed = 0; - pConfigs[2].transparentGreen = 0; - pConfigs[2].transparentBlue = 0; - pConfigs[2].transparentAlpha = 0; - pConfigs[2].transparentIndex = 0; - - pConfigs[3].vid = -1; - pConfigs[3].class = -1; - pConfigs[3].rgba = TRUE; - pConfigs[3].redSize = 8; - pConfigs[3].greenSize = 8; - pConfigs[3].blueSize = 8; - pConfigs[3].redMask = 0x00FF0000; - pConfigs[3].greenMask = 0x0000FF00; - pConfigs[3].blueMask = 0x000000FF; - pConfigs[3].alphaMask = 0; - pConfigs[3].accumRedSize = 0; - pConfigs[3].accumGreenSize = 0; - pConfigs[3].accumBlueSize = 0; - pConfigs[3].accumAlphaSize = 0; - pConfigs[3].doubleBuffer = TRUE; - pConfigs[3].stereo = FALSE; - pConfigs[3].bufferSize = 16; - pConfigs[3].depthSize = 16; - pConfigs[3].stencilSize = 0; - pConfigs[3].auxBuffers = 0; - pConfigs[3].level = 0; - pConfigs[3].visualRating = 0; - pConfigs[3].transparentPixel = 0; - pConfigs[3].transparentRed = 0; - pConfigs[3].transparentGreen = 0; - pConfigs[3].transparentBlue = 0; - pConfigs[3].transparentAlpha = 0; - pConfigs[3].transparentIndex = 0; - break; - } - pMGA->numVisualConfigs = numConfigs; - pMGA->pVisualConfigs = pConfigs; - pMGA->pVisualConfigsPriv = pMGAConfigs; - GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pMGAConfigPtrs); - return TRUE; +static unsigned int mylog2(unsigned int n) +{ + unsigned int log2 = 1; + while (n>1) n >>= 1, log2++; + return log2; } + Bool MGADRIScreenInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; @@ -224,10 +247,24 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) DRIInfoPtr pDRIInfo; MGADRIPtr pMGADRI; MGADRIServerPrivatePtr pMGADRIServer; - int bufs; - int prim_size; - int init_offset; + int bufs, size; + int prim_size; + int init_offset; + int i; +#if XFree86LOADER + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for canonical symbols in each module. */ + if (!LoaderSymbol("GlxSetVisualConfigs")) return FALSE; + if (!LoaderSymbol("DRIScreenInit")) return FALSE; + if (!LoaderSymbol("drmAvailable")) return FALSE; +#endif + + if((pScrn->bitsPerPixel / 8) != 2) { + ErrorF("Direct Rendering only supported in 16 bpp mode\n"); + return FALSE; + } + pDRIInfo = DRICreateInfoRec(); if (!pDRIInfo) return FALSE; pMGA->pDRIInfo = pDRIInfo; @@ -247,28 +284,25 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) pDRIInfo->frameBufferStride = pScrn->displayWidth*(pScrn->bitsPerPixel/8); pDRIInfo->ddxDrawableTableEntry = MGA_MAX_DRAWABLES; + MGADRIWrapFunctions( pScreen, pDRIInfo ); + if (SAREA_MAX_DRAWABLES < MGA_MAX_DRAWABLES) pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; else pDRIInfo->maxDrawableTableEntry = MGA_MAX_DRAWABLES; -#ifdef NOT_DONE - /* FIXME need to extend DRI protocol to pass this size back to client - * for SAREA mapping that includes a device private record - */ - pDRIInfo->SAREASize = - ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */ - /* + shared memory device private rec */ -#else /* For now the mapping works by using a fixed size defined * in the SAREA header */ - if (sizeof(XF86DRISAREARec)+sizeof(drm_mga_sarea_t)>SAREA_MAX) { + if (sizeof(XF86DRISAREARec)+sizeof(MGASAREARec)>SAREA_MAX) { ErrorF("Data does not fit in SAREA\n"); return FALSE; } + + ErrorF("\n\n\nSarea %d+%d: %d\n", sizeof(XF86DRISAREARec), + sizeof(MGASAREARec), sizeof(XF86DRISAREARec) + sizeof(MGASAREARec)); + pDRIInfo->SAREASize = SAREA_MAX; -#endif if (!(pMGADRI = (MGADRIPtr)xnfcalloc(sizeof(MGADRIRec),1))) { DRIDestroyInfoRec(pMGA->pDRIInfo); @@ -277,7 +311,7 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) return FALSE; } if (!(pMGADRIServer = (MGADRIServerPrivatePtr) - xnfcalloc(sizeof(MGADRIServerPrivate),1))) { + xnfcalloc(sizeof(MGADRIServerPrivateRec),1))) { xfree(pMGADRI); DRIDestroyInfoRec(pMGA->pDRIInfo); pMGA->pDRIInfo=0; @@ -334,25 +368,44 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) pMGADRIServer->regs); /* Agp Support */ + pMGADRIServer->agpAcquired = FALSE; + pMGADRIServer->agpHandle = 0; + pMGADRIServer->agpSizep = 0; + pMGADRIServer->agp_map = 0; + if(drmAgpAcquire(pMGA->drmSubFD) < 0) { DRICloseScreen(pScreen); ErrorF("drmAgpAcquire failed\n"); return FALSE; } + pMGADRIServer->agpAcquired = TRUE; + pMGADRIServer->warp_ucode_size = mgaGetMicrocodeSize(pScreen); if(pMGADRIServer->warp_ucode_size == 0) { ErrorF("microcodeSize is zero\n"); DRICloseScreen(pScreen); return FALSE; } + + pMGADRIServer->agpMode = drmAgpGetMode(pMGA->drmSubFD); + /* Default to 1X agp mode */ + pMGADRIServer->agpMode &= ~0x00000002; + if (drmAgpEnable(pMGA->drmSubFD, pMGADRIServer->agpMode) < 0) { + ErrorF("drmAgpEnable failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + ErrorF("drmAgpEnabled succeeded\n"); prim_size = 65536; init_offset = ((prim_size + pMGADRIServer->warp_ucode_size + 4096 - 1) / 4096) * 4096; - pMGADRIServer->agpSizep = drmAgpSize(pMGA->drmSubFD); - pMGADRIServer->agpBase = drmAgpBase(pMGA->drmSubFD); - if (drmAddMap(pMGA->drmSubFD, (drmHandle)pMGADRIServer->agpBase, + pMGADRIServer->agpSizep = init_offset; + pMGADRI->agpSize = (drmAgpSize(pMGA->drmSubFD)) - init_offset; + + pMGADRIServer->agpBase = (drmAddress) drmAgpBase(pMGA->drmSubFD); + if (drmAddMap(pMGA->drmSubFD, 0, init_offset, DRM_AGP, 0, &pMGADRIServer->agp_private) < 0) { DRICloseScreen(pScreen); @@ -370,12 +423,15 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) /* Now allocate and bind a default of 8 megs */ - pMGADRIServer->agpHandle = drmAgpAlloc(pMGA->drmSubFD, 0x00800000, 0, 0); + drmAgpAlloc(pMGA->drmSubFD, 0x00800000, 0, 0, + &pMGADRIServer->agpHandle); + if(pMGADRIServer->agpHandle == 0) { ErrorF("drmAgpAlloc failed\n"); DRICloseScreen(pScreen); return FALSE; } + if(drmAgpBind(pMGA->drmSubFD, pMGADRIServer->agpHandle, 0) < 0) { DRICloseScreen(pScreen); ErrorF("drmAgpBind failed\n"); @@ -384,72 +440,121 @@ Bool MGADRIScreenInit(ScreenPtr pScreen) mgaInstallMicrocode(pScreen, prim_size); - ErrorF("init_offset: %x\n", init_offset); - pMGADRI->agpSize = pMGADRIServer->agpSizep - init_offset; - ErrorF("pMGADRI->agpSize: %x\n", pMGADRI->agpSize); - - if(drmAddMap(pMGA->drmSubFD, (drmHandle)pMGADRIServer->agpBase + init_offset, + if(drmAddMap(pMGA->drmSubFD, (drmHandle)init_offset, pMGADRI->agpSize, DRM_AGP, 0, &pMGADRI->agp) < 0) { ErrorF("Failed to map public agp area\n"); DRICloseScreen(pScreen); return FALSE; } - ErrorF("Mapped public agp area\n"); + + + switch(pMGA->Chipset) { + case PCI_CHIP_MGAG400: + pMGADRI->chipset = MGA_CARD_TYPE_G400; + break; + case PCI_CHIP_MGAG200: + pMGADRI->chipset = MGA_CARD_TYPE_G200; + break; + case PCI_CHIP_MGAG200_PCI: + default: + ErrorF("Direct rendering not supported on this card/chipset\n"); + return FALSE; + } + + + pMGADRI->width = pScrn->virtualX; + pMGADRI->height = pScrn->virtualY; + pMGADRI->mem = pScrn->videoRam * 1024; + pMGADRI->cpp = pScrn->bitsPerPixel / 8; + pMGADRI->frontPitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8); + + + pMGADRI->frontOffset = 0; /* pMGA->YDstOrg * (pScrn->bitsPerPixel / 8) */ + pMGADRI->backOffset = ((pScrn->virtualY+129) * pScrn->displayWidth * + (pScrn->bitsPerPixel / 8) + 4095) & ~0xFFF; + + + fprintf(stderr, "calced backoffset: 0x%x\n", + pMGADRI->backOffset); + + +#if 0 + size = 2 * pScrn->virtualX * pScrn->virtualY; + pMGADRI->depthOffset = (pMGADRI->backOffset + size + 4095) & ~0xFFF; + pMGADRI->textureOffset = pMGADRI->depthOffset + size; + pMGADRI->textureSize = pMGA->FbUsableSize - pMGADRI->textureOffset; +#else + size = 2 * pScrn->virtualX * pScrn->virtualY; + size += 4095; + size &= ~4095; + pMGADRI->depthOffset = pMGA->FbUsableSize - size; + pMGADRI->depthOffset &= ~4095; + pMGADRI->textureOffset = pMGADRI->backOffset + size; + pMGADRI->textureSize = pMGADRI->depthOffset - pMGADRI->textureOffset; + + if (pMGADRI->depthOffset < pMGADRI->textureOffset + 512*1024) { + ErrorF("Insufficient memory for direct rendering\n"); + DRICloseScreen(pScreen); + return FALSE; + } +#endif + + pMGADRI->mAccess = pMGA->MAccess; + + i = mylog2(pMGADRI->textureSize / MGA_NR_TEX_REGIONS); + if (i < MGA_LOG_MIN_TEX_REGION_SIZE) + i = MGA_LOG_MIN_TEX_REGION_SIZE; + + pMGADRI->logTextureGranularity = i; + pMGADRI->textureSize = (pMGADRI->textureSize >> i) << i; /* truncate */ + + /* Here is where we need to do initialization of the dma engine */ - - pMGADRIServer->agpMode = drmAgpGetMode(pMGA->drmSubFD); - /* Default to 1X agp mode */ - pMGADRIServer->agpMode &= ~0x00000002; - if (drmAgpEnable(pMGA->drmSubFD, pMGADRIServer->agpMode) < 0) { - ErrorF("drmAgpEnable failed\n"); - DRICloseScreen(pScreen); - return FALSE; - } - ErrorF("drmAgpEnabled succeeded\n"); - if((bufs = drmAddBufs(pMGA->drmSubFD, - /*63*/ 15, - /* 65536 */ 524288, + if((bufs = drmAddBufs(pMGA->drmSubFD, + MGA_DMA_BUF_NR, + MGA_DMA_BUF_SZ, DRM_AGP_BUFFER, init_offset)) <= 0) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] failure adding %d %d byte DMA buffers\n", - /* 63 */ 15, - /* 65536 */ 524288); + MGA_DMA_BUF_NR, + MGA_DMA_BUF_SZ); DRICloseScreen(pScreen); return FALSE; } + + pMGADRI->agpBufferOffset = init_offset + pMGADRIServer->agp_private; + + /* Calculate texture constants for AGP texture space + */ + { + CARD32 agpTextureOffset = MGA_DMA_BUF_SZ * MGA_DMA_BUF_NR; + CARD32 agpTextureSize = pMGADRI->agpSize - agpTextureOffset; + + i = mylog2(agpTextureSize / MGA_NR_TEX_REGIONS); + if (i < MGA_LOG_MIN_TEX_REGION_SIZE) + i = MGA_LOG_MIN_TEX_REGION_SIZE; + + pMGADRI->logAgpTextureGranularity = i; + pMGADRI->agpTextureSize = (agpTextureSize >> i) << i; + pMGADRI->agpTextureOffset = agpTextureOffset; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] added %d %d byte DMA buffers\n", - bufs, /* 65536 */ 524288); + bufs, MGA_DMA_BUF_SZ); - if((mgadrmInitDma(pScrn, prim_size)) != TRUE) { + if((MgaInitDma(pScrn, prim_size)) != TRUE) { ErrorF("Failed to initialize dma engine\n"); DRICloseScreen(pScreen); return FALSE; } - - ErrorF("Initialized Dma Engine\n"); + ErrorF("Initialized Dma Engine\n"); - if(drmMarkBufs(pMGA->drmSubFD, 0.133333, 0.266666) != 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "[drm] failure marking DMA buffers\n"); - DRICloseScreen(pScreen); - return FALSE; - } - if (!(pMGADRIServer->drmBufs = drmMapBufs(pMGA->drmSubFD))) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "[drm] failure mapping DMA buffers\n"); - DRICloseScreen(pScreen); - return FALSE; - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] buffers mapped with %p\n", - pMGADRIServer->drmBufs); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] %d DMA buffers mapped\n", - pMGADRIServer->drmBufs->count); if (!pMGADRIServer->irq) { pMGADRIServer->irq = drmGetInterruptFromBusID(pMGA->drmSubFD, ((pciConfigPtr)pMGA->PciInfo @@ -481,16 +586,26 @@ MGADRICloseScreen(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; MGAPtr pMGA = MGAPTR(pScrn); MGADRIServerPrivatePtr pMGADRIServer = pMGA->DRIServerInfo; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "[drm] unmapping %d buffers\n", - pMGADRIServer->drmBufs->count); - if (drmUnmapBufs(pMGADRIServer->drmBufs)) { - xf86DrvMsg(pScreen->myNum, X_INFO, - "[drm] unable to unmap DMA buffers\n"); + + MgaCleanupDma(pScrn); + + if(pMGADRIServer->agp_map) { + ErrorF("Unmapped agp region\n"); + drmUnmap(pMGADRIServer->agp_map, pMGADRIServer->agpSizep); + pMGADRIServer->agp_map = 0; } - mgadrmCleanupDma(pScrn); - + if(pMGADRIServer->agpHandle) { + ErrorF("Freeing agp memory\n"); + drmAgpFree(pMGA->drmSubFD, pMGADRIServer->agpHandle); + pMGADRIServer->agpHandle = 0; + pMGADRIServer->agpSizep = 0; + } + if(pMGADRIServer->agpAcquired == TRUE) { + ErrorF("releasing agp module\n"); + drmAgpRelease(pMGA->drmSubFD); + pMGADRIServer->agpAcquired = FALSE; + } + DRICloseScreen(pScreen); if (pMGA->pDRIInfo) { @@ -518,9 +633,6 @@ MGACreateContext(ScreenPtr pScreen, VisualPtr visual, drmContext hwContext, void *pVisualConfigPriv, DRIContextType contextStore) { - MGADRIContextPtr ctx; - - ctx = (MGADRIContextPtr)contextStore; return TRUE; } @@ -528,106 +640,120 @@ static void MGADestroyContext(ScreenPtr pScreen, drmContext hwContext, DRIContextType contextStore) { - MGADRIContextPtr ctx; - ctx = (MGADRIContextPtr)contextStore; } Bool MGADRIFinishScreenInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MGASAREAPtr sPriv; MGAPtr pMGA = MGAPTR(pScrn); - MGADRIPtr pMGADRI; - int size; + if (!pMGA->pDRIInfo) return FALSE; + + sPriv = (MGASAREAPtr)DRIGetSAREAPrivate(pScreen); pMGA->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; - /* pMGA->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */ - pMGADRI = (MGADRIPtr)pMGA->pDRIInfo->devPrivate; - pMGADRI->deviceID = pMGA->PciInfo->chipType; - pMGADRI->width = pScrn->virtualX; - pMGADRI->height = pScrn->virtualY; - pMGADRI->mem = pScrn->videoRam * 1024; - pMGADRI->cpp = pScrn->bitsPerPixel / 8; - pMGADRI->stride = pScrn->displayWidth * (pScrn->bitsPerPixel / 8); - pMGADRI->backOffset = ((pScrn->virtualY+129) * pScrn->displayWidth * - (pScrn->bitsPerPixel / 8) + 4095) & ~0xFFF; - size = 2 * pScrn->virtualX * pScrn->virtualY; - pMGADRI->depthOffset = (pMGADRI->backOffset + size + 4095) & ~0xFFF; - pMGADRI->textureOffset = pMGADRI->depthOffset + size; - /* - * The rest of the framebuffer is for textures except for the - * memory for the hardware cursor. - */ - pMGADRI->textureSize = pMGA->FbUsableSize - pMGADRI->textureOffset; - pMGADRI->fbOffset = pMGA->YDstOrg * (pScrn->bitsPerPixel / 8); + xf86memset( sPriv, 0, sizeof(MGASAREARec) ); return DRIFinishScreenInit(pScreen); } -void MGASwapContext(ScreenPtr pScreen) + +void mgaGetQuiescence( ScrnInfoPtr pScrn ) { -#if 0 - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - MGAPtr pMga = MGAPTR(pScrn); - MGAFBLayout *pLayout = &pMga->CurrentLayout; - - usleep(500); - ErrorF("Syncing : swap\n"); - MGABUSYWAIT(); - ErrorF("Sync : swap 1\n"); - MGAStormSync(pScrn); - ErrorF("Syncing done\n"); - pMga->AccelInfoRec->NeedToSync = TRUE; - - WAITFIFO(12); - OUTREG(MGAREG_MACCESS, pMga->MAccess); - OUTREG(MGAREG_PITCH, pLayout->displayWidth); - OUTREG(MGAREG_YDSTORG, pMga->YDstOrg); - OUTREG(MGAREG_PLNWT, pMga->PlaneMask); - OUTREG(MGAREG_BCOL, pMga->BgColor); - OUTREG(MGAREG_FCOL, pMga->FgColor); - OUTREG(MGAREG_SRCORG, pMga->SrcOrg); - OUTREG(MGAREG_DSTORG, pMga->DstOrg); - OUTREG(MGAREG_OPMODE, MGAOPM_DMA_BLIT); - OUTREG(MGAREG_CXBNDRY, 0xFFFF0000); /* (maxX << 16) | minX */ - OUTREG(MGAREG_YTOP, 0x00000000); /* minPixelPointer */ - OUTREG(MGAREG_YBOT, 0x007FFFFF); /* maxPixelPointer */ - pMga->AccelFlags &= ~CLIPPER_ON; -#endif + MGAPtr pMga = MGAPTR(pScrn); + + pMga->have_quiescense = 1; + + if (pMga->directRenderingEnabled) { + MGAFBLayout *pLayout = &pMga->CurrentLayout; + + MgaLockUpdate(pScrn, (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH)); + + WAITFIFO(12); + OUTREG(MGAREG_MACCESS, pMga->MAccess); + OUTREG(MGAREG_PITCH, pLayout->displayWidth); + OUTREG(MGAREG_YDSTORG, pMga->YDstOrg); + OUTREG(MGAREG_PLNWT, pMga->PlaneMask); + OUTREG(MGAREG_BCOL, pMga->BgColor); + OUTREG(MGAREG_FCOL, pMga->FgColor); + OUTREG(MGAREG_SRCORG, pMga->SrcOrg); + OUTREG(MGAREG_DSTORG, pMga->DstOrg); + OUTREG(MGAREG_OPMODE, MGAOPM_DMA_BLIT); + OUTREG(MGAREG_CXBNDRY, 0xFFFF0000); /* (maxX << 16) | minX */ + OUTREG(MGAREG_YTOP, 0x00000000); /* minPixelPointer */ + OUTREG(MGAREG_YBOT, 0x007FFFFF); /* maxPixelPointer */ + pMga->AccelFlags &= ~CLIPPER_ON; + } } -void MGALostContext(ScreenPtr pScreen) + + +void MGASwapContext(ScreenPtr pScreen) { -#if 0 - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - MGAPtr pMga = MGAPTR(pScrn); - MGAFBLayout *pLayout = &pMga->CurrentLayout; - - ErrorF("Syncing : lost\n"); - MGAStormSync(pScrn); - ErrorF("Sync : lost 1\n"); - MGABUSYWAIT(); - ErrorF("Syncing done\n"); -#endif + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MGAPtr pMga = MGAPTR(pScrn); + + /* Arrange for dma_quiescence and xaa sync to be called as + * appropriate. + */ + pMga->have_quiescense = 0; + pMga->AccelInfoRec->NeedToSync = TRUE; } + + +/* This is really only called from validate/postvalidate as we + * override the dri lock/unlock. Want to remove validate/postvalidate + * processing, but need to remove all client-side use of drawable lock + * first (otherwise there is noone recover when a client dies holding + * the drawable lock). + * + * What does this mean? + * + * - The above code gets executed every time a + * window changes shape or the focus changes, which isn't really + * optimal. + * - The X server therefore believes it needs to do an XAA sync + * *and* a dma quiescense ioctl each time that happens. + * + * We don't wrap wakeuphandler any longer, so at least we can say that + * this doesn't happen *every time the mouse moves*... + */ static void MGADRISwapContext(ScreenPtr pScreen, DRISyncType syncType, DRIContextType oldContextType, void *oldContext, DRIContextType newContextType, void *newContext) { - if ((syncType == DRI_3D_SYNC) && (oldContextType == DRI_2D_CONTEXT) && - (newContextType == DRI_2D_CONTEXT)) { /* Entering from Wakeup */ - MGASwapContext(pScreen); - } - if ((syncType == DRI_2D_SYNC) && (oldContextType == DRI_NO_CONTEXT) && - (newContextType == DRI_2D_CONTEXT)) { /* Exiting from Block Handler */ - MGALostContext(pScreen); - } + if (syncType == DRI_3D_SYNC && + oldContextType == DRI_2D_CONTEXT && + newContextType == DRI_2D_CONTEXT) + { + MGASwapContext(pScreen); + } } -/* Needs to be written */ -void MGASelectBuffer(MGAPtr pMGA, int which) + +void +MGASelectBuffer(ScrnInfoPtr pScrn, int which) { + MGAPtr pMga = MGAPTR(pScrn); + MGADRIPtr pMGADRI = (MGADRIPtr)pMga->pDRIInfo->devPrivate; + + switch (which) { + case MGA_BACK: + OUTREG(MGAREG_DSTORG, pMGADRI->backOffset); + OUTREG(MGAREG_SRCORG, pMGADRI->backOffset); + break; + case MGA_DEPTH: + OUTREG(MGAREG_DSTORG, pMGADRI->depthOffset); + OUTREG(MGAREG_SRCORG, pMGADRI->depthOffset); + break; + default: + case MGA_FRONT: + OUTREG(MGAREG_DSTORG, pMGADRI->frontOffset); + OUTREG(MGAREG_SRCORG, pMGADRI->frontOffset); + break; + } } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.h b/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.h index 7196bc954..b8518ee89 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_dri.h @@ -4,9 +4,11 @@ #define _MGA_DRI_ #include <xf86drm.h> -#include "mga_drm_public.h" +#include <xf86drmMga.h> -typedef struct _mga_dri_server_private { +#define MGA_MAX_DRAWABLES 256 + +typedef struct { int reserved_map_agpstart; int reserved_map_idx; int buffer_map_idx; @@ -17,6 +19,7 @@ typedef struct _mga_dri_server_private { int sgram; unsigned long agpMode; unsigned long agpHandle; + Bool agpAcquired; drmHandle agp_private; drmSize agpSizep; drmAddress agpBase; @@ -24,27 +27,115 @@ typedef struct _mga_dri_server_private { drmHandle regs; drmSize regsSize; drmAddress regsMap; - mgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; + drmMgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; drmBufMapPtr drmBufs; CARD8 *agp_map; -} MGADRIServerPrivate, *MGADRIServerPrivatePtr; +} MGADRIServerPrivateRec, *MGADRIServerPrivatePtr; typedef struct { - int deviceID; - int width; - int height; - int mem; - int cpp; - int stride; - int fbOffset; - int backOffset; - int depthOffset; - int textureOffset; - int textureSize; - drmHandle agp; - drmSize agpSize; + int chipset; + int width; + int height; + int mem; + int cpp; + unsigned int frontOffset; + unsigned int frontPitch; + + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + unsigned int textureOffset; + unsigned int textureSize; + int logTextureGranularity; + + /* Allow calculation of setup dma addresses. + */ + unsigned int agpBufferOffset; + + unsigned int agpTextureOffset; + unsigned int agpTextureSize; + int logAgpTextureGranularity; + + /* Redundant? + */ + unsigned int frontOrg; + unsigned int backOrg; + unsigned int depthOrg; + + unsigned int mAccess; + + drmHandle agp; + drmSize agpSize; } MGADRIRec, *MGADRIPtr; +/* WARNING: Do not change the SAREA structure without changing the kernel + * as well */ +typedef struct { + unsigned char next, prev; + unsigned char in_use; + unsigned int age; +} MGATexRegionRec, *MGATexRegionPtr; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex dma buffer. + */ + unsigned int ContextState[MGA_CTX_SETUP_SIZE]; + unsigned int ServerState[MGA_2D_SETUP_SIZE]; + unsigned int TexState[2][MGA_TEX_SETUP_SIZE]; + unsigned int WarpPipe; + unsigned int dirty; + + unsigned int nbox; + XF86DRIClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS]; + + /* Information about the most recently used 3d drawable. The + * client fills in the req_* fields, the server fills in the + * exported_ fields and puts the cliprects into boxes, above. + * + * The client clears the exported_drawable field before + * clobbering the boxes data. + */ + unsigned int req_drawable; /* the X drawable id */ + unsigned int req_draw_buffer; /* MGA_FRONT or MGA_BACK */ + + unsigned int exported_drawable; + unsigned int exported_index; + unsigned int exported_stamp; + unsigned int exported_buffers; + unsigned int exported_nfront; + unsigned int exported_nback; + int exported_back_x, exported_front_x, exported_w; + int exported_back_y, exported_front_y, exported_h; + XF86DRIClipRectRec exported_boxes[MGA_NR_SAREA_CLIPRECTS]; + + /* Counters for aging textures and for client-side throttling. + */ + unsigned int last_enqueue; /* last time a buffer was enqueued */ + unsigned int last_dispatch; /* age of the most recently dispatched buffer */ + unsigned int last_quiescent; /* */ + + /* LRU lists for texture memory in agp space and on the card */ + + MGATexRegionRec texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS+1]; + unsigned int texAge[MGA_NR_TEX_HEAPS]; + /* Mechanism to validate card state. + */ + int ctxOwner; +} MGASAREARec, *MGASAREAPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} MGAConfigPrivRec, *MGAConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} MGADRIContextRec, *MGADRIContextPtr; #endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/Imakefile b/xc/programs/Xserver/hw/xfree86/drivers/r128/Imakefile index e3f7178bf..8f0f33a35 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/Imakefile +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/Imakefile @@ -6,9 +6,16 @@ XCOMM #define IHaveModules #include <Server.tmpl> -SRCS = r128_driver.c r128_cursor.c r128_accel.c # r128_i2c.c +#if BuildXF86DRI +DRISRCS = r128_dri.c +DRIOBJS = r128_dri.o +DRIINCLUDES = -I$(SERVERSRC)/GL/dri -I$(LIBSRC)/GL/dri +DRIDEFINES = $(GLX_DEFINES) +#endif + +SRCS = r128_driver.c r128_cursor.c r128_accel.c $(DRISRCS) # r128_i2c.c -OBJS = r128_driver.o r128_cursor.o r128_accel.o # r128_i2c.o +OBJS = r128_driver.o r128_cursor.o r128_accel.o $(DRIOBJS) # r128_i2c.o #if defined(XF86DriverSDK) INCLUDES = -I. -I../../include @@ -22,9 +29,12 @@ INCLUDES = -I. -I$(XF86COMSRC) -I$(XF86OSSRC) \ -I$(XF86SRC)/ddc -I$(XF86SRC)/i2c -I$(XF86OSSRC)/vbe \ -I$(XF86SRC)/int10 -I$(SERVERSRC)/Xext \ -I$(FONTINCSRC) -I$(SERVERSRC)/include -I$(XINCLUDESRC) \ - -I$(EXTINCSRC) -I$(XF86SRC)/xf24_32bpp + -I$(EXTINCSRC) -I$(XF86SRC)/xf24_32bpp \ + $(DRIINCLUDES) #endif +DEFINES = $(DRIDEFINES) + #if MakeHasPosixVariableSubstitutions SubdirLibraryRule($(OBJS)) #endif @@ -49,5 +59,10 @@ InstallDriverSDKNonExecFile(r128_cursor.c,$(DRIVERSDKDIR)/drivers/r128) InstallDriverSDKNonExecFile(r128_driver.c,$(DRIVERSDKDIR)/drivers/r128) InstallDriverSDKNonExecFile(r128_reg.h,$(DRIVERSDKDIR)/drivers/r128) +InstallDriverSDKNonExecFile(r128_dri.c,$(DRIVERSDKDIR)/drivers/r128) +InstallDriverSDKNonExecFile(r128_dri.h,$(DRIVERSDKDIR)/drivers/r128) +InstallDriverSDKNonExecFile(r128_dripriv.h,$(DRIVERSDKDIR)/drivers/r128) +InstallDriverSDKNonExecFile(r128_sarea.h,$(DRIVERSDKDIR)/drivers/r128) + InstallDriverSDKObjectModule(r128,$(DRIVERSDKMODULEDIR),drivers) diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128.h b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128.h index d5d120153..acb04f96e 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128.h @@ -1,8 +1,8 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/r128/r128.h,v 1.8 2000/02/23 04:47:18 martin Exp $ */ /************************************************************************** -Copyright 1999 ATI Technologies Inc. and Precision Insight, Inc., - Cedar Park, Texas. +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a @@ -40,6 +40,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define R128_TIMEOUT 2000000 /* Fall out of wait loops after this count */ #define R128_MMIOSIZE 0x80000 + /* R128_NAME is used for the server-side + ddx driver, the client-side DRI driver, + and the kernel-level DRM driver. */ #define R128_NAME "r128" #define R128_VERSION_MAJOR 3 #define R128_VERSION_MINOR 0 @@ -157,7 +160,7 @@ typedef struct { unsigned char *FB; /* Map of frame buffer */ CARD32 MemCntl; - CARD32 BusCntl; + CARD32 BusCntl; unsigned long FbMapSize; /* Size of frame buffer, in bytes */ int Flags; /* Saved copy of mode flags */ @@ -168,6 +171,8 @@ typedef struct { R128SaveRec ModeReg; /* Current mode */ Bool (*CloseScreen)(int, ScreenPtr); + Bool PaletteSavedOnVT; /* Palette saved on last VT switch */ + I2CBusPtr i2c; XAAInfoRecPtr accel; xf86CursorInfoPtr cursor; @@ -199,8 +204,98 @@ typedef struct { int scanline_words; int scanline_direct; int scanline_bpp; /* Only used for ImageWrite */ + +#ifdef XF86DRI + Bool directRenderingEnabled; + DRIInfoPtr pDRIInfo; + int drmFD; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + R128ConfigPrivPtr pVisualConfigsPriv; + + drmHandle fbHandle; + + drmSize registerSize; + drmHandle registerHandle; + + Bool IsPCI; /* Current card is a PCI card */ + + drmSize agpSize; + drmHandle agpMemHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + unsigned char *AGP; /* Map */ + int agpMode; + + Bool CCEInUse; /* CCE is currently active */ + int CCEMode; /* CCE mode that server/clients use */ + int CCEFifoSize; /* Size of the CCE command FIFO */ + Bool CCESecure; /* CCE security enabled */ + int CCEusecTimeout; /* CCE timeout in usecs */ + Bool CCE2D; /* CCE is used for X server 2D prims */ + + /* CCE ring buffer data */ + unsigned long ringStart; /* Offset into AGP space */ + drmHandle ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in MB) */ + unsigned char *ring; /* Map */ + int ringSizeLog2QW; + + unsigned long ringReadOffset; /* Offset into AGP space */ + drmHandle ringReadPtrHandle; /* Handle from drmAddMap */ + drmSize ringReadMapSize; /* Size of map */ + unsigned char *ringReadPtr; /* Map */ + + /* CCE vertex buffer data */ + unsigned long vbStart; /* Offset into AGP space */ + drmHandle vbHandle; /* Handle from drmAddMap */ + drmSize vbMapSize; /* Size of map */ + int vbSize; /* Size of vert bufs (in MB) */ + unsigned char *vb; /* Map */ + int vbBufSize; /* Size of individual vert buf */ + int vbNumBufs; /* Number of vert bufs */ + drmBufMapPtr vbBufs; /* Buffer map */ + + /* CCE indirect buffer data */ + unsigned long indStart; /* Offset into AGP space */ + drmHandle indHandle; /* Handle from drmAddMap */ + drmSize indMapSize; /* Size of map */ + int indSize; /* Size of indirect bufs (in MB) */ + unsigned char *ind; /* Map */ + + /* CCE AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drmHandle agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + unsigned char *agpTex; /* Map */ + int log2AGPTexGran; + + /* DRI screen private data */ + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + int textureX; + int textureY; + int textureSize; + int log2TexGran; +#endif } R128InfoRec, *R128InfoPtr; +#define R128WaitForFifo(pScrn, entries) \ +do { \ + if (info->fifo_slots < entries) R128WaitForFifoFunction(pScrn, entries); \ + info->fifo_slots -= entries; \ +} while (0) + +extern void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries); +extern void R128WaitForIdle(ScrnInfoPtr pScrn); +extern void R128EngineReset(ScrnInfoPtr pScrn); +extern void R128EngineFlush(ScrnInfoPtr pScrn); + extern int INPLL(ScrnInfoPtr pScrn, int addr); extern void R128WaitForVerticalSync(ScrnInfoPtr pScrn); @@ -208,4 +303,16 @@ extern Bool R128AccelInit(ScreenPtr pScreen); extern void R128EngineInit(ScrnInfoPtr pScrn); extern Bool R128CursorInit(ScreenPtr pScreen); +extern int R128MinBits(int val); + +#ifdef XF86DRI +extern Bool R128DRIScreenInit(ScreenPtr pScreen); +extern void R128DRICloseScreen(ScreenPtr pScreen); +extern Bool R128DRIFinishScreenInit(ScreenPtr pScreen); +extern void R128CCEStart(ScrnInfoPtr pScrn); +extern void R128CCEStop(ScrnInfoPtr pScrn); +extern void R128CCEResetRing(ScrnInfoPtr pScrn); +extern void R128CCEWaitForIdle(ScrnInfoPtr pScrn); +#endif + #endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_accel.c b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_accel.c index 5b0223661..f42569767 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_accel.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_accel.c @@ -1,8 +1,8 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/r128/r128_accel.c,v 1.7 2000/02/23 04:47:18 martin Exp $ */ /************************************************************************** -Copyright 1999 ATI Technologies Inc. and Precision Insight, Inc., - Cedar Park, Texas. +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a @@ -95,6 +95,19 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* DDC support */ #include "xf86DDC.h" + /* DRI support */ +#ifdef XF86DRI +#include "GL/glxint.h" +#include "xf86drm.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "r128_dri.h" +#include "r128_dripriv.h" +#include "r128_sarea.h" +#endif + /* Driver data structures */ #include "r128.h" #include "r128_reg.h" @@ -122,7 +135,7 @@ static struct { }; /* Flush all dirty data in the Pixel Cache to memory. */ -static void R128EngineFlush(ScrnInfoPtr pScrn) +void R128EngineFlush(ScrnInfoPtr pScrn) { int i; R128MMIO_VARS(); @@ -134,11 +147,12 @@ static void R128EngineFlush(ScrnInfoPtr pScrn) } /* Reset graphics card to known state. */ -static void R128EngineReset(ScrnInfoPtr pScrn) +void R128EngineReset(ScrnInfoPtr pScrn) { - CARD32 clock_cntl_index; - CARD32 mclk_cntl; - CARD32 gen_reset_cntl; + R128InfoPtr info = R128PTR(pScrn); + CARD32 clock_cntl_index; + CARD32 mclk_cntl; + CARD32 gen_reset_cntl; R128MMIO_VARS(); R128EngineFlush(pScrn); @@ -158,17 +172,15 @@ static void R128EngineReset(ScrnInfoPtr pScrn) OUTPLL(R128_MCLK_CNTL, mclk_cntl); OUTREG(R128_CLOCK_CNTL_INDEX, clock_cntl_index); OUTREG(R128_GEN_RESET_CNTL, gen_reset_cntl); -} -#define R128WaitForFifo(pScrn, entries) \ -do { \ - if (info->fifo_slots < entries) R128WaitForFifoFunction(pScrn, entries); \ - info->fifo_slots -= entries; \ -} while (0) +#ifdef XF86DRI + if (R128CCE_USE_RING_BUFFER(info->CCEMode)) R128CCEResetRing(pScrn); +#endif +} /* The FIFO has 64 slots. This routines waits until at least `entries' of these slots are empty. */ -static void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries) +void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries) { R128InfoPtr info = R128PTR(pScrn); int i; @@ -186,15 +198,19 @@ static void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "FIFO timed out, resetting engine...\n"); R128EngineReset(pScrn); +#if XF86DRI + if (info->CCE2D) R128CCEStart(pScrn); +#endif } } /* Wait for the graphics engine to be completely idle: the FIFO has drained, the Pixel Cache is flushed, and the engine is idle. This is a standard "sync" function that will make the hardware "quiescent". */ -static void R128WaitForIdle(ScrnInfoPtr pScrn) +void R128WaitForIdle(ScrnInfoPtr pScrn) { - int i; + R128InfoPtr info = R128PTR(pScrn); + int i; R128MMIO_VARS(); R128WaitForFifoFunction(pScrn, 64); @@ -213,6 +229,9 @@ static void R128WaitForIdle(ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Idle timed out, resetting engine...\n"); R128EngineReset(pScrn); +#if XF86DRI + if (info->CCE2D) R128CCEStart(pScrn); +#endif } } @@ -966,19 +985,33 @@ void R128EngineInit(ScrnInfoPtr pScrn) OUTREG(R128_DP_SRC_BKGD_CLR, 0x00000000); OUTREG(R128_DP_WRITE_MASK, 0xffffffff); +#if X_BYTE_ORDER == X_BIG_ENDIAN + OUTREGP(R128_DP_DATATYPE, + R128_HOST_BIG_ENDIAN_EN, ~R128_HOST_BIG_ENDIAN_EN); +#else + OUTREGP(R128_DP_DATATYPE, 0, ~R128_HOST_BIG_ENDIAN_EN); +#endif + R128WaitForIdle(pScrn); } -/* Initialize XAA for supported acceleration and also initialize the - graphics hardware for acceleration. */ -Bool R128AccelInit(ScreenPtr pScreen) +#ifdef XF86DRI + /* FIXME: When direct rendering is enabled, we should use the CCE to + draw 2D commands */ +static void R128CCEAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - R128InfoPtr info = R128PTR(pScrn); - XAAInfoRecPtr a; + a->Flags = 0; + + /* Sync */ + a->Sync = R128CCEWaitForIdle; + +} +#endif + +static void R128MMIOAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a) +{ + R128InfoPtr info = R128PTR(pScrn); - if (!(a = info->accel = XAACreateInfoRec())) return FALSE; - a->Flags = (PIXMAP_CACHE | OFFSCREEN_PIXMAPS | LINEAR_FRAMEBUFFER); @@ -1065,7 +1098,26 @@ Bool R128AccelInit(ScreenPtr pScreen) | SCANLINE_PAD_DWORD | SYNC_AFTER_IMAGE_WRITE); #endif - +} + +/* Initialize XAA for supported acceleration and also initialize the + graphics hardware for acceleration. */ +Bool R128AccelInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + XAAInfoRecPtr a; + + if (!(a = info->accel = XAACreateInfoRec())) return FALSE; + +#ifdef XF86DRI + /* FIXME: When direct rendering is enabled, we should use the CCE to + draw 2D commands */ + if (info->CCE2D) R128CCEAccelInit(pScrn, a); + else +#endif + R128MMIOAccelInit(pScrn, a); + R128EngineInit(pScrn); return XAAInit(pScreen, a); } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_cursor.c b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_cursor.c index a96872702..2667443d9 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_cursor.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_cursor.c @@ -1,8 +1,8 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/r128/r128_cursor.c,v 1.6 2000/03/06 22:59:26 dawes Exp $ */ /************************************************************************** -Copyright 1999 ATI Technologies Inc. and Precision Insight, Inc., - Cedar Park, Texas. +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a @@ -60,6 +60,19 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* DDC support */ #include "xf86DDC.h" + /* DRI support */ +#ifdef XF86DRI +#include "GL/glxint.h" +#include "xf86drm.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "r128_dri.h" +#include "r128_dripriv.h" +#include "r128_sarea.h" +#endif + /* Driver data structures */ #include "r128.h" #include "r128_reg.h" @@ -92,16 +105,19 @@ static void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) (xorigin,yorigin). */ static void R128SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) { - R128InfoPtr info = R128PTR(pScrn); - int xorigin = 0; - int yorigin = 0; - int total_y = pScrn->frameY1 - pScrn->frameY0; + R128InfoPtr info = R128PTR(pScrn); + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int total_y = pScrn->frameY1 - pScrn->frameY0; R128MMIO_VARS(); - if (x < 0) xorigin = -x; - if (y < 0) yorigin = -y; - if (y > total_y) y = total_y; - if (info->Flags & V_DBLSCAN) y *= 2; + if (x < 0) xorigin = -x; + if (y < 0) yorigin = -y; + if (y > total_y) y = total_y; + if (info->Flags & V_DBLSCAN) y *= 2; + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; OUTREG(R128_CUR_HORZ_VERT_OFF, R128_CUR_LOCK | (xorigin << 16) | yorigin); OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK @@ -126,47 +142,58 @@ static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) #if X_BYTE_ORDER == X_BIG_ENDIAN switch(info->pixel_bytes) { - case 4: - case 3: - for (y = 0; y < 64; y++) { - P_SWAP32(d,s); - d++; s++; - P_SWAP32(d,s); - d++; s++; - P_SWAP32(d,s); - d++; s++; - P_SWAP32(d,s); - d++; s++; - } - break; - case 2: - for (y = 0; y < 64; y++) { - P_SWAP16(d,s); - d++; s++; - P_SWAP16(d,s); - d++; s++; - P_SWAP16(d,s); - d++; s++; - P_SWAP16(d,s); - d++; s++; - } - break; - default: - for (y = 0; y < 64; y++) { + case 4: + case 3: + for (y = 0; y < 64; y++) { + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + } + break; + case 2: + for (y = 0; y < 64; y++) { + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + } + break; + default: + for (y = 0; y < 64; y++) { *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; - } + } } #else - for (y = 0; y < 64; y++) { + for (y = 0; y < 64; y++) { *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; } #endif + + /* Set the area after the cursor to be all transparent so that we + won't display corrupted cursors on the screen */ + for (y = 0; y < 64; y++) { + *d++ = 0xffffffff; /* The AND bits */ + *d++ = 0xffffffff; + *d++ = 0x00000000; /* The XOR bits */ + *d++ = 0x00000000; + } + + OUTREG(R128_CRTC_GEN_CNTL, save); } @@ -204,6 +231,7 @@ Bool R128CursorInit(ScreenPtr pScreen) FBAreaPtr fbarea; int width; int height; + int size; if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE; @@ -227,8 +255,9 @@ Bool R128CursorInit(ScreenPtr pScreen) cursor->ShowCursor = R128ShowCursor; cursor->UseHWCursor = R128UseHWCursor; + size = (cursor->MaxWidth/4) * cursor->MaxHeight; width = pScrn->displayWidth; - height = (1024 + 1023) / pScrn->displayWidth; + height = (size*2 + 1023) / pScrn->displayWidth; fbarea = xf86AllocateOffscreenArea(pScreen, width, height, @@ -246,7 +275,7 @@ Bool R128CursorInit(ScreenPtr pScreen) info->cursor_start = R128_ALIGN((fbarea->box.x1 + width * fbarea->box.y1) * info->pixel_bytes, 16); - info->cursor_end = info->cursor_start + 1024; + info->cursor_end = info->cursor_start + size; } R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n", diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.c b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.c new file mode 100644 index 000000000..cb647d6b6 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.c @@ -0,0 +1,1242 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * Rickard E. Faith <faith@precisioninsight.com> + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + + + /* X and server generic header files */ +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" +#include "xf86fbman.h" + + /* Backing store, software cursor, and + colormap initialization */ +#include "mibstore.h" +#include "mipointer.h" +#include "micmap.h" + + /* CFB support */ +#define PSZ 8 +#include "cfb.h" +#undef PSZ +#include "cfb16.h" +#include "cfb24.h" +#include "cfb32.h" +#include "cfb24_32.h" + + /* XAA and Cursor Support */ +#include "xaa.h" +#include "xf86Cursor.h" + + /* PCI support */ +#include "xf86PciInfo.h" +#include "xf86Pci.h" + + /* DDC support */ +#include "xf86DDC.h" + + /* DRI support */ +#include "GL/glxint.h" +#include "GL/glxtokens.h" +#include "xf86drm.h" +#include "xf86drmR128.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "r128_dri.h" +#include "r128_sarea.h" +#include "r128_dripriv.h" + + /* Driver data structures */ +#include "r128.h" +#include "r128_reg.h" + +#define R128_WATERMARK_L 16 +#define R128_WATERMARK_M 8 +#define R128_WATERMARK_N 8 +#define R128_WATERMARK_K 128 + +static int CCEFifoSlots = 0; + +#define R128CCEWaitForFifo(pScrn, entries) \ +do { \ + if (CCEFifoSlots < entries) R128WaitForFifoFunction(pScrn, entries); \ + CCEFifoSlots -= entries; \ +} while (0) + +/* Wait for at least `entries' slots are free. The actual number of + slots available is stored in info->CCEFifoSize. */ +static void R128CCEWaitForFifoFunction(ScrnInfoPtr pScrn, int entries) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + for (;;) { + for (i = 0; i < R128_TIMEOUT; i++) { + CCEFifoSlots = INREG(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK; + if (CCEFifoSlots >= entries) return; + } + R128EngineReset(pScrn); + if (info->CCE2D) R128CCEStart(pScrn); + } +} + +/* Wait until the CCE is completely idle: the FIFO has drained and the + CCE is idle. */ +void R128CCEWaitForIdle(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + if (!info->CCEInUse || info->CCEMode == R128_PM4_NONPM4) return; + + if (R128CCE_USE_RING_BUFFER(info->CCEMode)) { + volatile CARD32 *r128RingReadPtr = + (volatile CARD32 *)(info->ringReadPtr); + R128SAREAPrivPtr pSAREAPriv; + + OUTREGP(R128_PM4_BUFFER_DL_WPTR, + R128_PM4_BUFFER_DL_DONE, ~R128_PM4_BUFFER_DL_DONE); + + pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScrn->pScreen); + + for (;;) { + for (i = 0; i < R128_TIMEOUT; i++) { + if (*r128RingReadPtr == pSAREAPriv->ringWrite) { + int pm4stat = INREG(R128_PM4_STAT); + if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= info->CCEFifoSize + && !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) + return; + } + } + R128EngineReset(pScrn); + if (info->CCE2D) R128CCEStart(pScrn); + } + } else { + R128CCEWaitForFifoFunction(pScrn, info->CCEFifoSize); + + for (;;) { + for (i = 0; i < R128_TIMEOUT; i++) { + if (!(INREG(R128_PM4_STAT) + & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { + R128EngineFlush(pScrn); + return; + } + } + R128EngineReset(pScrn); + if (info->CCE2D) R128CCEStart(pScrn); + } + } +} + +/* Reset the ring buffer status, if the engine was reset */ +void R128CCEResetRing(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128SAREAPrivPtr pSAREAPriv; + volatile CARD32 *r128RingReadPtr; + + if (!info->CCEInUse || info->CCEMode == R128_PM4_NONPM4) return; + + r128RingReadPtr = (volatile CARD32 *)(info->ringReadPtr); + pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScrn->pScreen); + + OUTREG(R128_PM4_BUFFER_DL_WPTR, 0); + OUTREG(R128_PM4_BUFFER_DL_RPTR, 0); + pSAREAPriv->ringWrite = 0; + *r128RingReadPtr = 0; + + /* Resetting the ring turns off the CCE */ + info->CCEInUse = FALSE; +} + +/* Start the CCE, but only if it is not already in use and the requested + mode is a CCE mode. The mode is stored in info->CCEMode. */ +void R128CCEStart(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if (info->CCEInUse || info->CCEMode == R128_PM4_NONPM4) return; + + R128WaitForIdle(pScrn); + OUTREG(R128_PM4_BUFFER_CNTL, info->CCEMode | info->ringSizeLog2QW); + (void)INREG(R128_PM4_BUFFER_ADDR); /* as per the sample code */ + OUTREG(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); + info->CCEInUse = TRUE; +} + +/* Stop the CCE, but only if it is in use and the requested mode is not + the non-CCE mode. This function also flushes any outstanding + requests before switching modes.*/ +void R128CCEStop(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if (!info->CCEInUse || info->CCEMode == R128_PM4_NONPM4) return; + + R128CCEWaitForIdle(pScrn); + OUTREG(R128_PM4_MICRO_CNTL, 0); + OUTREG(R128_PM4_BUFFER_CNTL, R128_PM4_NONPM4); + R128EngineReset(pScrn); + info->CCEInUse = FALSE; +} + +/* Initialize the visual configs that are supported by the hardware. + These are combined with the visual configs that the indirect + rendering core supports, and the intersection is exported to the + client. */ +static Bool R128InitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + R128ConfigPrivPtr pR128Configs = 0; + R128ConfigPrivPtr *pR128ConfigPtrs = 0; + int i, accum, stencil; + + switch (pR128->pixel_code) { + case 8: /* 8bpp mode is not support */ + case 15: /* FIXME */ + case 24: /* FIXME */ + return FALSE; + +#define R128_USE_ACCUM 1 +#define R128_USE_STENCIL 0 /* Only in 24 depth mode */ + + case 16: + numConfigs = 1; + if (R128_USE_ACCUM) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig*)xnfcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pR128Configs + = (R128ConfigPrivPtr)xnfcalloc(sizeof(R128ConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pR128ConfigPtrs + = (R128ConfigPrivPtr*)xnfcalloc(sizeof(R128ConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pR128Configs); + return FALSE; + } + + i = 0; + for (accum = 0; accum <= R128_USE_ACCUM; accum++) { + pR128ConfigPtrs[i] = &pR128Configs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + + pConfigs[i].alphaMask = 0; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = TRUE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + pConfigs[i].depthSize = 16; + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum) + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + break; + case 32: + numConfigs = 1; + if (R128_USE_ACCUM) numConfigs *= 2; + if (R128_USE_STENCIL) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig*)xnfcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pR128Configs + = (R128ConfigPrivPtr)xnfcalloc(sizeof(R128ConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pR128ConfigPtrs + = (R128ConfigPrivPtr*)xnfcalloc(sizeof(R128ConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pR128Configs); + return FALSE; + } + + i = 0; + for (accum = 0; accum <= R128_USE_ACCUM; accum++) { + for (stencil = 0; stencil <= R128_USE_STENCIL; stencil++) { + pR128ConfigPtrs[i] = &pR128Configs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + + pConfigs[i].alphaMask = 0; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = TRUE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 24; + if (stencil) { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 32; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum) + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + break; + } + + pR128->numVisualConfigs = numConfigs; + pR128->pVisualConfigs = pConfigs; + pR128->pVisualConfigsPriv = pR128Configs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pR128ConfigPtrs); + return TRUE; +} + +/* Create the Rage 128-specific context information */ +static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + /* Nothing yet */ + return TRUE; +} + +/* Destroy the Rage 128-specific context information */ +static void R128DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ + /* Nothing yet */ +} + +/* Called when the X server is woken up to allow the last client's + context to be saved and the X server's context to be loaded. This is + not necessary for the Rage 128 since the client detects when it's + context is not currently loaded and then load's it itself. Since the + registers to start and stop the CCE are privileged, only the X server + can start/stop the engine. */ +static void R128EnterServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + + if (pR128->accel) pR128->accel->NeedToSync = TRUE; + +#if 1 + if (!pR128->CCE2D) R128CCEStop(pScrn); +#else + if (pR128->CCE2D) R128CCEWaitForIdle(pScrn); + else R128CCEStop(pScrn); +#endif +} + +/* Called when the X server goes to sleep to allow the X server's + context to be saved and the last client's context to be loaded. This + is not necessary for the Rage 128 since the client detects when it's + context is not currently loaded and then load's it itself. Since the + registers to start and stop the CCE are privileged, only the X server + can start/stop the engine. */ +static void R128LeaveServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + +#if 1 + if (!pR128->CCE2D) R128CCEStart(pScrn); +#else + if (pR128->CCE2D) R128CCEWaitForIdle(pScrn); + else R128CCEStart(pScrn); +#endif +} + +/* Contexts can be swapped by the X server if necessary. This callback + is currently only used to perform any functions necessary when + entering or leaving the X server, and in the future might not be + necessary. */ +static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, void *oldContext, + DRIContextType newContextType, void *newContext) +{ + if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */ + R128EnterServer(pScreen); + } + if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */ + R128LeaveServer(pScreen); + } +} + +/* Initialize the state of the back and depth buffers. */ +static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index) +{ + /* FIXME: This routine needs to have acceleration turned on */ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + BoxPtr pbox; + int nbox; + int depth; + + /* FIXME: Use accel when CCE 2D code is written */ + if (pR128->CCE2D) return; + + /* FIXME: This should be based on the __GLXvisualConfig info */ + switch (pScrn->bitsPerPixel) { + case 8: depth = 0x000000ff; break; + case 16: depth = 0x0000ffff; break; + case 24: depth = 0x00ffffff; break; + case 32: depth = 0xffffffff; break; + default: depth = 0x00000000; break; + } + + /* FIXME: Copy XAAPaintWindow() and use REGION_TRANSLATE() */ + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + pbox = REGION_RECTS(prgn); + nbox = REGION_NUM_RECTS(prgn); + + (*pR128->accel->SetupForSolidFill)(pScrn, 0, GXcopy, -1); + for (; nbox; nbox--, pbox++) { + (*pR128->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + pR128->fbX, + pbox->y1 + pR128->fbY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + (*pR128->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + pR128->backX, + pbox->y1 + pR128->backY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + (*pR128->accel->SetupForSolidFill)(pScrn, depth, GXcopy, -1); + for (; nbox; nbox--, pbox++) + (*pR128->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + pR128->depthX, + pbox->y1 + pR128->depthY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + + pR128->accel->NeedToSync = TRUE; +} + +/* Copy the back and depth buffers when the X server moves a window. */ +static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + + /* FIXME: This routine needs to have acceleration turned on */ + /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */ + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + /* FIXME: Use accel when CCE 2D code is written */ + if (pR128->CCE2D) return; +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + initialize the Rage 128 registers to point to that memory. */ +static Bool R128DRIAgpInit(R128InfoPtr pR128, ScreenPtr pScreen) +{ + unsigned char *R128MMIO = pR128->MMIO; + unsigned long mode; + unsigned int vendor, device; + int ret; + unsigned long cntl; + int s, l; + int flags; + + if (drmAgpAcquire(pR128->drmFD) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not available\n"); + return FALSE; + } + + /* Modify the mode if the default mode is + not appropriate for this particular + combination of graphics card and AGP + chipset. */ + + mode = drmAgpGetMode(pR128->drmFD); /* Default mode */ + vendor = drmAgpVendorId(pR128->drmFD); + device = drmAgpDeviceId(pR128->drmFD); + + mode &= ~R128_AGP_MODE_MASK; + switch (pR128->agpMode) { + case 2: mode |= R128_AGP_2X_MODE; + case 1: default: mode |= R128_AGP_1X_MODE; + } + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + pR128->PciInfo->vendor, + pR128->PciInfo->chipType); + + if (drmAgpEnable(pR128->drmFD, mode) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n"); + drmAgpRelease(pR128->drmFD); + return FALSE; + } + + pR128->agpOffset = 0; + + if ((ret = drmAgpAlloc(pR128->drmFD, pR128->agpSize*1024*1024, 0, NULL, + &pR128->agpMemHandle)) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret); + drmAgpRelease(pR128->drmFD); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] %d kB allocated with handle 0x%08x\n", + pR128->agpSize*1024, pR128->agpMemHandle); + + if (drmAgpBind(pR128->drmFD, pR128->agpMemHandle, pR128->agpOffset) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n"); + drmAgpFree(pR128->drmFD, pR128->agpMemHandle); + drmAgpRelease(pR128->drmFD); + return FALSE; + } + + /* Initialize the CCE ring buffer data */ + pR128->ringStart = pR128->agpOffset; + pR128->ringMapSize = pR128->ringSize*1024*1024 + 4096; + pR128->ringSizeLog2QW = R128MinBits(pR128->ringSize*1024*1024/8) - 1; + + pR128->ringReadOffset = pR128->ringStart + pR128->ringMapSize; + pR128->ringReadMapSize = 4096; + + /* Reserve space for the vertex buffer */ + pR128->vbStart = pR128->ringReadOffset + pR128->ringReadMapSize; + pR128->vbMapSize = pR128->vbSize*1024*1024; + + /* Reserve space for the indirect buffer */ + pR128->indStart = pR128->vbStart + pR128->vbMapSize; + pR128->indMapSize = pR128->indSize*1024*1024; + + /* Reserve the rest for AGP textures */ + pR128->agpTexStart = pR128->indStart + pR128->indMapSize; + s = (pR128->agpSize*1024*1024 - pR128->agpTexStart); + l = R128MinBits((s-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + pR128->agpTexMapSize = (s >> l) << l; + pR128->log2AGPTexGran = l; + + if (pR128->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + if (drmAddMap(pR128->drmFD, pR128->ringStart, pR128->ringMapSize, + DRM_AGP, flags, &pR128->ringHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring handle = 0x%08lx\n", pR128->ringHandle); + + if (drmMap(pR128->drmFD, pR128->ringHandle, pR128->ringMapSize, + (drmAddressPtr)&pR128->ring) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)pR128->ring); + + if (drmAddMap(pR128->drmFD, pR128->ringReadOffset, pR128->ringReadMapSize, + DRM_AGP, flags, &pR128->ringReadPtrHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring read ptr mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring read ptr handle = 0x%08lx\n", + pR128->ringReadPtrHandle); + + if (drmMap(pR128->drmFD, pR128->ringReadPtrHandle, pR128->ringReadMapSize, + (drmAddressPtr)&pR128->ringReadPtr) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map ring read ptr\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)pR128->ringReadPtr); + + if (drmAddMap(pR128->drmFD, pR128->vbStart, pR128->vbMapSize, + DRM_AGP, 0, &pR128->vbHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add vertex buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] vertex buffers handle = 0x%08lx\n", pR128->vbHandle); + + if (drmMap(pR128->drmFD, pR128->vbHandle, pR128->vbMapSize, + (drmAddressPtr)&pR128->vb) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map vertex buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Vertex buffers mapped at 0x%08lx\n", + (unsigned long)pR128->vb); + + if (drmAddMap(pR128->drmFD, pR128->indStart, pR128->indMapSize, + DRM_AGP, flags, &pR128->indHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add indirect buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] indirect buffers handle = 0x%08lx\n", pR128->indHandle); + + if (drmMap(pR128->drmFD, pR128->indHandle, pR128->indMapSize, + (drmAddressPtr)&pR128->ind) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map indirect buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Indirect buffers mapped at 0x%08lx\n", + (unsigned long)pR128->ind); + + if (drmAddMap(pR128->drmFD, pR128->agpTexStart, pR128->agpTexMapSize, + DRM_AGP, 0, &pR128->agpTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add AGP texture map mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP texture map handle = 0x%08lx\n", + pR128->agpTexHandle); + + if (drmMap(pR128->drmFD, pR128->agpTexHandle, pR128->agpTexMapSize, + (drmAddressPtr)&pR128->agpTex) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map AGP texture map\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP Texture map mapped at 0x%08lx\n", + (unsigned long)pR128->agpTex); + + /* Initialize Rage 128's AGP registers */ + cntl = INREG(R128_AGP_CNTL); + cntl &= ~R128_AGP_APER_SIZE_MASK; + switch (pR128->agpSize) { + case 256: cntl |= R128_AGP_APER_SIZE_256MB; break; + case 128: cntl |= R128_AGP_APER_SIZE_128MB; break; + case 64: cntl |= R128_AGP_APER_SIZE_64MB; break; + case 32: cntl |= R128_AGP_APER_SIZE_32MB; break; + case 16: cntl |= R128_AGP_APER_SIZE_16MB; break; + case 8: cntl |= R128_AGP_APER_SIZE_8MB; break; + case 4: cntl |= R128_AGP_APER_SIZE_4MB; break; + default: + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d kB\n", + pR128->agpSize*1024); + return FALSE; + } + OUTREG(R128_AGP_BASE, pR128->ringHandle); /* Ring buf is at AGP offset 0 */ + OUTREG(R128_AGP_CNTL, cntl); + + return TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + DRI-based clients. */ +static Bool R128DRIMapInit(R128InfoPtr pR128, ScreenPtr pScreen) +{ + int flags; + + if (pR128->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + /* Map registers */ + pR128->registerSize = R128_MMIOSIZE; + if (drmAddMap(pR128->drmFD, pR128->MMIOAddr, pR128->registerSize, + DRM_REGISTERS, flags, &pR128->registerHandle) < 0) { + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] register handle = 0x%08lx\n", pR128->registerHandle); + + return TRUE; +} + +/* Initialize the ring buffer state for use in the X server and any + DRI-based clients. */ +static void R128DRICCEInitRingBuffer(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + unsigned long addr; + + /* FIXME: When we use the CCE for the X server, we should move this + function (and the support functions above) to r128_accel.c */ + + /* The manual (p. 2) says this address is + in "VM space". This means it's an + offset from the start of AGP space. */ + OUTREG(R128_PM4_BUFFER_OFFSET, info->ringStart | 0x02000000); + + OUTREG(R128_PM4_BUFFER_DL_WPTR, 0); + OUTREG(R128_PM4_BUFFER_DL_RPTR, 0); + + /* DL_RPTR_ADDR is a physical address. + This should be in the SAREA. */ + *(volatile long unsigned *)(info->ringReadPtr) = 0; + OUTREG(R128_PM4_BUFFER_DL_RPTR_ADDR, (info->ringReadPtrHandle)); + + /* Set watermark control */ + OUTREG(R128_PM4_BUFFER_WM_CNTL, + ((R128_WATERMARK_L/4) << R128_WMA_SHIFT) + | ((R128_WATERMARK_M/4) << R128_WMB_SHIFT) + | ((R128_WATERMARK_N/4) << R128_WMC_SHIFT) + | ((R128_WATERMARK_K/64) << R128_WB_WM_SHIFT)); + + addr = INREG(R128_PM4_BUFFER_ADDR); /* Force read. Why? Because it's + in the examples... */ + +#if 0 + R128CCEWaitForIdle(pScrn); +#endif + + /* Turn on bus mastering */ + info->BusCntl &= ~R128_BUS_MASTER_DIS; + OUTREGP(R128_BUS_CNTL, 0, ~R128_BUS_MASTER_DIS); +} + +/* Initialize the kernel data structures. */ +static int R128DRIKernelInit(R128InfoPtr pR128, ScreenPtr pScreen) +{ + drmR128Init drmInfo; + + drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec); + drmInfo.is_pci = pR128->IsPCI; + drmInfo.cce_mode = pR128->CCEMode; + drmInfo.cce_fifo_size = pR128->CCEFifoSize; + drmInfo.cce_secure = pR128->CCESecure; + drmInfo.ring_size = pR128->ringSize*1024*1024; + drmInfo.usec_timeout = pR128->CCEusecTimeout; + + drmInfo.fb_offset = pR128->LinearAddr; + drmInfo.agp_ring_offset = pR128->ringHandle; + drmInfo.agp_read_ptr_offset = pR128->ringReadPtrHandle; + drmInfo.agp_vertbufs_offset = pR128->vbHandle; + drmInfo.agp_indbufs_offset = pR128->indHandle; + drmInfo.agp_textures_offset = pR128->agpTexHandle; + drmInfo.mmio_offset = pR128->registerHandle; + + if (drmR128InitCCE(pR128->drmFD, &drmInfo) < 0) return FALSE; + + return TRUE; +} + +/* Add a map for the vertex buffers that will be accessed by any + DRI-based clients. */ +static Bool R128DRIBufInit(R128InfoPtr pR128, ScreenPtr pScreen) +{ + /* Initialize vertex buffers */ + if ((pR128->vbNumBufs = drmAddBufs(pR128->drmFD, + pR128->vbMapSize / pR128->vbBufSize, + pR128->vbBufSize, + DRM_AGP_BUFFER, + pR128->vbStart)) <= 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Could not create vertex buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Added %d %d byte vertex buffers\n", + pR128->vbNumBufs, pR128->vbBufSize); + + if (drmMarkBufs(pR128->drmFD, 0.133333, 0.266666)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Failed to mark vertex buffers list\n"); + return FALSE; + } + + if (!(pR128->vbBufs = drmMapBufs(pR128->drmFD))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Failed to map vertex buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Mapped %d vertex buffers\n", + pR128->vbBufs->count); + + return TRUE; +} + +/* Load the microcode for the CCE */ +static void R128DRILoadMicrocode(ScrnInfoPtr pScrn) +{ + unsigned char *R128MMIO = R128PTR(pScrn)->MMIO; + int i; + unsigned long R128Microcode[] = { + /* CCE microcode (from ATI) */ + 0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0, 1617039951, + 0, 774592877, 0, 1987540286, 0, 2307490946U, 0, 599558925, 0, 589505315, 0, + 596487092, 0, 589505315, 1, 11544576, 1, 206848, 1, 311296, 1, 198656, 2, + 912273422, 11, 262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, + 28, 1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9, 30, 1, + 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656, 1, 15630, 1, 51200, + 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1, 15717, 1, 15718, 2, 43, 1, + 15936948, 1, 570480831, 1, 14715071, 12, 322123831, 1, 33953125, 12, 55, 1, + 33559908, 1, 15718, 2, 46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, + 509952, 1, 459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1, + 18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1, 15975928, 1, + 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2, 268449859, 2, 10307, 12, + 176, 1, 15734, 1, 15735, 1, 15630, 1, 15631, 1, 5253120, 6, 3145810, 16, + 2150645232U, 1, 15864, 2, 82, 1, 343310, 1, 1064207, 2, 3145813, 1, 15728, + 1, 7817, 1, 15729, 3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, + 1, 16008, 1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0, + 15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1, 180224, 1, + 103824738, 2, 112, 2, 3145839, 0, 536885440, 1, 114880, 14, 125, 12, + 206975, 1, 33559995, 12, 198784, 0, 33570236, 1, 15803, 0, 15804, 3, + 294912, 1, 294912, 3, 442370, 1, 11544576, 0, 811612160, 1, 12593152, 1, + 11536384, 1, 14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, + 14793, 1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1, + 198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1, 114880, 14, + 159, 12, 198784, 1, 1109409213, 12, 198783, 1, 1107312059, 12, 198784, 1, + 1109409212, 2, 162, 1, 1075854781, 1, 1073757627, 1, 1075854780, 1, 540672, + 1, 10485760, 6, 3145894, 16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, + 0, 0, 256, 14, 174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, + 1, 33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1, 33560360, 1, + 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1, 409611, 9, 188, 0, + 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }; + + R128WaitForIdle(pScrn); + + OUTREG(R128_PM4_MICROCODE_ADDR, 0); + for (i = 0; i < 256; i += 1) { + OUTREG(R128_PM4_MICROCODE_DATAH, R128Microcode[i*2]); + OUTREG(R128_PM4_MICROCODE_DATAL, R128Microcode[i*2 + 1]); + } +} + +/* Initialize the CCE state, and start the CCE (if used by the X server) */ +static void R128DRICCEInit(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + /* CCEMode is initialized in r128_driver.c */ + switch (info->CCEMode) { + case R128_PM4_NONPM4: info->CCEFifoSize = 0; break; + case R128_PM4_192PIO: info->CCEFifoSize = 192; break; + case R128_PM4_192BM: info->CCEFifoSize = 192; break; + case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break; + } + + if (info->CCE2D) { + /* Make sure the CCE is on for the X server */ + R128CCEStart(pScrn); + } else { + /* Make sure the CCE is off for the X server */ + OUTREG(R128_PM4_MICRO_CNTL, 0); + OUTREG(R128_PM4_BUFFER_CNTL, R128_PM4_NONPM4); + } +} + +/* Initialize the screen-specific data structures for the DRI and the + Rage 128. This is the main entry point to the device-specific + initialization code. It calls device-independent DRI functions to + create the DRI data structures and initialize the DRI state. */ +Bool R128DRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + DRIInfoPtr pDRIInfo; + R128DRIPtr pR128DRI; + + switch (pR128->pixel_code) { + case 8: + /* These modes are not supported (yet). */ + case 15: + case 24: + return FALSE; + + /* Only 16 and 32 color depths are supports currently. */ + case 16: + case 32: + break; + } + + /* Create the DRI data structure, and fill it in before calling the + DRIScreenInit(). */ + if (!(pDRIInfo = DRICreateInfoRec())) return FALSE; + + pR128->pDRIInfo = pDRIInfo; + pDRIInfo->drmDriverName = R128_NAME; + pDRIInfo->clientDriverName = R128_NAME; + pDRIInfo->busIdString = xalloc(64); + sprintf(pDRIInfo->busIdString, + "PCI:%d:%d:%d", + pR128->PciInfo->bus, + pR128->PciInfo->device, + pR128->PciInfo->func); + pDRIInfo->ddxDriverMajorVersion = R128_VERSION_MAJOR; + pDRIInfo->ddxDriverMinorVersion = R128_VERSION_MINOR; + pDRIInfo->ddxDriverPatchVersion = R128_VERSION_PATCH; + pDRIInfo->frameBufferPhysicalAddress = pR128->LinearAddr; + pDRIInfo->frameBufferSize = pR128->FbMapSize; + pDRIInfo->frameBufferStride = (pScrn->displayWidth + * pR128->pixel_bytes); + pDRIInfo->ddxDrawableTableEntry = R128_MAX_DRAWABLES; + pDRIInfo->maxDrawableTableEntry = (SAREA_MAX_DRAWABLES + < R128_MAX_DRAWABLES + ? SAREA_MAX_DRAWABLES + : R128_MAX_DRAWABLES); + +#ifdef NOT_DONE + /* FIXME: Need to extend DRI protocol to pass this size back to + * client for SAREA mapping that includes a device private record + */ + pDRIInfo->SAREASize = + ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */ + /* + shared memory device private rec */ +#else + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) { + ErrorF("Data does not fit in SAREA\n"); + return FALSE; + } + pDRIInfo->SAREASize = SAREA_MAX; +#endif + + if (!(pR128DRI = (R128DRIPtr)xnfcalloc(sizeof(R128DRIRec),1))) { + DRIDestroyInfoRec(pR128->pDRIInfo); + pR128->pDRIInfo = NULL; + return FALSE; + } + pDRIInfo->devPrivate = pR128DRI; + pDRIInfo->devPrivateSize = sizeof(R128DRIRec); + pDRIInfo->contextSize = sizeof(R128DRIContextRec); + + pDRIInfo->CreateContext = R128CreateContext; + pDRIInfo->DestroyContext = R128DestroyContext; + pDRIInfo->SwapContext = R128DRISwapContext; + pDRIInfo->InitBuffers = R128DRIInitBuffers; + pDRIInfo->MoveBuffers = R128DRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + + if (!DRIScreenInit(pScreen, pDRIInfo, &pR128->drmFD)) { + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec(pDRIInfo); + pDRIInfo = NULL; + return FALSE; + } + + /* Initialize AGP */ + if (!pR128->IsPCI && !R128DRIAgpInit(pR128, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* DRIScreenInit doesn't add all the + common mappings. Add additional + mappings here. */ + if (!R128DRIMapInit(pR128, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize the ring buffer */ + if (!pR128->IsPCI) R128DRICCEInitRingBuffer(pScrn); + + /* Initialize the kernel data structures */ + if (!R128DRIKernelInit(pR128, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize vertex buffers list */ + if (!pR128->IsPCI && !R128DRIBufInit(pR128, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* FIXME: When are these mappings unmapped? */ + + if (!R128InitVisualConfigs(pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Visual configs initialized\n"); + + /* Load the CCE Microcode */ + R128DRILoadMicrocode(pScrn); + + /* Reset the Graphics Engine */ + R128EngineReset(pScrn); + + return TRUE; +} + +/* Finish initializing the device-dependent DRI state, and call + DRIFinishScreenInit() to complete the device-independent DRI + initialization. */ +Bool R128DRIFinishScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + R128SAREAPrivPtr pSAREAPriv; + R128DRIPtr pR128DRI; + + /* Init and start the CCE */ + R128DRICCEInit(pScrn); + + pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen); + memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); + + pR128->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + /* pR128->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */ + + pR128DRI = (R128DRIPtr)pR128->pDRIInfo->devPrivate; + pR128DRI->registerHandle = pR128->registerHandle; + pR128DRI->registerSize = pR128->registerSize; + + pR128DRI->ringHandle = pR128->ringHandle; + pR128DRI->ringMapSize = pR128->ringMapSize; + pR128DRI->ringSize = pR128->ringSize*1024*1024; + + pR128DRI->ringReadPtrHandle = pR128->ringReadPtrHandle; + pR128DRI->ringReadMapSize = pR128->ringReadMapSize; + + pR128DRI->vbHandle = pR128->vbHandle; + pR128DRI->vbMapSize = pR128->vbMapSize; + pR128DRI->vbOffset = pR128->vbStart; + pR128DRI->vbBufSize = pR128->vbBufSize; + + pR128DRI->indHandle = pR128->indHandle; + pR128DRI->indMapSize = pR128->indMapSize; + + pR128DRI->agpTexHandle = pR128->agpTexHandle; + pR128DRI->agpTexMapSize = pR128->agpTexMapSize; + pR128DRI->log2AGPTexGran = pR128->log2AGPTexGran; + pR128DRI->agpTexOffset = pR128->agpTexStart; + + pR128DRI->deviceID = pR128->Chipset; + pR128DRI->width = pScrn->virtualX; + pR128DRI->height = pScrn->virtualY; + pR128DRI->depth = pScrn->depth; + pR128DRI->bpp = pScrn->bitsPerPixel; + + pR128DRI->fbX = pR128->fbX; + pR128DRI->fbY = pR128->fbY; + pR128DRI->backX = pR128->backX; + pR128DRI->backY = pR128->backY; + pR128DRI->depthX = pR128->depthX; + pR128DRI->depthY = pR128->depthY; + pR128DRI->textureX = pR128->textureX; + pR128DRI->textureY = pR128->textureY; + pR128DRI->textureSize = pR128->textureSize; + pR128DRI->log2TexGran = pR128->log2TexGran; + + pR128DRI->IsPCI = pR128->IsPCI; + + pR128DRI->CCEMode = pR128->CCEMode; + pR128DRI->CCEFifoSize = pR128->CCEFifoSize; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%08lx %d\n", + pR128DRI->registerHandle, pR128DRI->registerSize); + return DRIFinishScreenInit(pScreen); +} + +/* The screen is being closed, so clean up any state and free any + resources used by the DRI. */ +void R128DRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr pR128 = R128PTR(pScrn); + + /* Stop the CCE if it is still in use */ + if (pR128->CCE2D) R128CCEStop(pScrn); + + /* De-allocate vertex buffers */ + if (pR128->vbBufs) { + drmUnmapBufs(pR128->vbBufs); + pR128->vbBufs = NULL; + } + + /* De-allocate all kernel resources */ + drmR128CleanupCCE(pR128->drmFD); + + /* De-allocate all AGP resources */ + if (pR128->agpTex) { + drmUnmap(pR128->agpTex, pR128->agpTexMapSize); + pR128->agpTex = NULL; + } + if (pR128->ind) { + drmUnmap(pR128->ind, pR128->indMapSize); + pR128->ind = NULL; + } + if (pR128->vb) { + drmUnmap(pR128->vb, pR128->vbMapSize); + pR128->vb = NULL; + } + if (pR128->ringReadPtr) { + drmUnmap(pR128->ringReadPtr, pR128->ringReadMapSize); + pR128->ringReadPtr = NULL; + } + if (pR128->ring) { + drmUnmap(pR128->ring, pR128->ringMapSize); + pR128->ring = NULL; + } + if (pR128->agpMemHandle) { + drmAgpUnbind(pR128->drmFD, pR128->agpMemHandle); + drmAgpFree(pR128->drmFD, pR128->agpMemHandle); + pR128->agpMemHandle = 0; + drmAgpRelease(pR128->drmFD); + } + + /* De-allocate all DRI resources */ + DRICloseScreen(pScreen); + + /* De-allocate all DRI data structures */ + if (pR128->pDRIInfo) { + if (pR128->pDRIInfo->devPrivate) { + xfree(pR128->pDRIInfo->devPrivate); + pR128->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec(pR128->pDRIInfo); + pR128->pDRIInfo = NULL; + } + if (pR128->pVisualConfigs) { + xfree(pR128->pVisualConfigs); + pR128->pVisualConfigs = NULL; + } + if (pR128->pVisualConfigsPriv) { + xfree(pR128->pVisualConfigsPriv); + pR128->pVisualConfigsPriv = NULL; + } +} diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.h b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.h new file mode 100644 index 000000000..533aadb2f --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dri.h @@ -0,0 +1,116 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * Rickard E. Faith <faith@precisioninsight.com> + * + */ + +#ifndef _R128_DRI_ +#define _R128_DRI_ + +#include <xf86drm.h> + +/* DRI Driver defaults */ +#define R128_DEFAULT_CCE_PIO_MODE R128_PM4_64PIO_64VCBM_64INDBM +#define R128_DEFAULT_CCE_BM_MODE R128_PM4_64BM_64VCBM_64INDBM +#define R128_DEFAULT_AGP_MODE 2 +#define R128_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */ +#define R128_DEFAULT_RING_SIZE 1 /* MB (must be page aligned) */ +#define R128_DEFAULT_VB_SIZE 1 /* MB (must be page aligned) */ +#define R128_DEFAULT_IND_SIZE 1 /* MB (must be page aligned) */ +#define R128_DEFAULT_AGP_TEX_SIZE 1 /* MB (must be page aligned) */ + +#define R128_DEFAULT_VB_BUF_SIZE 16384 /* bytes */ +#define R128_DEFAULT_CCE_TIMEOUT 10000 /* usecs */ + +#define R128_AGP_MAX_MODE 2 + +#define R128CCE_USE_RING_BUFFER(m) \ +(((m) == R128_PM4_192BM) || \ + ((m) == R128_PM4_128BM_64INDBM) || \ + ((m) == R128_PM4_64BM_128INDBM) || \ + ((m) == R128_PM4_64BM_64VCBM_64INDBM)) + +typedef struct { + /* MMIO register data */ + drmHandle registerHandle; + drmSize registerSize; + + /* CCE ring buffer data */ + drmHandle ringHandle; + drmSize ringMapSize; + int ringSize; + + /* CCE ring read pointer data */ + drmHandle ringReadPtrHandle; + drmSize ringReadMapSize; + + /* CCE vertex buffer data */ + drmHandle vbHandle; + drmSize vbMapSize; + int vbOffset; + int vbBufSize; + + /* CCE indirect buffer data */ + drmHandle indHandle; + drmSize indMapSize; + + /* CCE AGP Texture data */ + drmHandle agpTexHandle; + drmSize agpTexMapSize; + int log2AGPTexGran; + int agpTexOffset; + + /* DRI screen private data */ + int deviceID; /* PCI device ID */ + int width; /* Width in pixels of display */ + int height; /* Height in scanlines of display */ + int depth; /* Depth of display (8, 15, 16, 24) */ + int bpp; /* Bit depth of display (8, 16, 24, 32) */ + + int fbX; /* Start of frame buffer */ + int fbY; + int backX; /* Start of shared back buffer */ + int backY; + int depthX; /* Start of shared depth buffer */ + int depthY; + int textureX; /* Start of texture data in frame buffer */ + int textureY; + int textureSize; + int log2TexGran; + + int IsPCI; /* Current card is a PCI card */ + + int CCEMode; /* CCE mode that server/clients use */ + int CCEFifoSize; /* Size of the CCE command FIFO */ +} R128DRIRec, *R128DRIPtr; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dripriv.h b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dripriv.h new file mode 100644 index 000000000..acec5e269 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_dripriv.h @@ -0,0 +1,54 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Rickard E. Faith <faith@precisioninsight.com> + * Kevin E. Martin <kevin@precisioninsight.com> + * + */ + +#ifndef _R128_DRIPRIV_H_ +#define _R128_DRIPRIV_H_ + +#define R128_MAX_DRAWABLES 256 + +extern void GlxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **configprivs); + +typedef struct { + /* Nothing here yet */ + int dummy; +} R128ConfigPrivRec, *R128ConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} R128DRIContextRec, *R128DRIContextPtr; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_driver.c b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_driver.c index b5da4cb6e..f30d86aa8 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_driver.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_driver.c @@ -1,8 +1,8 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/r128/r128_driver.c,v 1.26 2000/03/06 23:17:44 martin Exp $ */ /************************************************************************** -Copyright 1999 ATI Technologies Inc. and Precision Insight, Inc., - Cedar Park, Texas. +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a @@ -107,6 +107,19 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* VESA support */ #include "vbe.h" + /* DRI support */ +#ifdef XF86DRI +#include "GL/glxint.h" +#include "xf86drm.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "r128_dri.h" +#include "r128_dripriv.h" +#include "r128_sarea.h" +#endif + /* Driver data structures */ #include "r128.h" #include "r128_reg.h" @@ -176,17 +189,41 @@ typedef enum { OPTION_HW_CURSOR, OPTION_DAC_6BIT, OPTION_DAC_8BIT, +#ifdef XF86DRI + OPTION_IS_PCI, + OPTION_CCE_PIO, + OPTION_NO_SECURITY, + OPTION_USEC_TIMEOUT, + OPTION_AGP_MODE, + OPTION_AGP_SIZE, + OPTION_RING_SIZE, + OPTION_VERT_SIZE, + OPTION_VBUF_SIZE, + OPTION_USE_CCE_2D, +#endif OPTION_FBDEV } R128Opts; static OptionInfoRec R128Options[] = { - { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, TRUE }, - { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE }, - { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE } + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, TRUE }, + { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE }, +#ifdef XF86DRI + { OPTION_IS_PCI, "ForcePCIMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CCE_PIO, "CCEPIOMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NO_SECURITY, "CCENoSecurity", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_USEC_TIMEOUT, "CCEusecTimeout", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_RING_SIZE, "RingSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_VERT_SIZE, "VBListSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_VBUF_SIZE, "VBSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_USE_CCE_2D, "UseCCEfor2D", OPTV_BOOLEAN, {0}, FALSE }, +#endif + { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } }; R128RAMRec R128RAM[] = { /* Memory Specifications @@ -299,6 +336,38 @@ static const char *ramdacSymbols[] = { NULL }; +#ifdef XF86DRI +static const char *drmSymbols[] = { + "drmAddBufs", + "drmAddMap", + "drmAvailable", + "drmCtlAddCommand", + "drmCtlInstHandler", + "drmGetInterruptFromBusID", + "drmMapBufs", + "drmMarkBufs", + "drmUnmapBufs", + NULL +}; + +static const char *driSymbols[] = { + "DRIGetDrawableIndex", + "DRIFinishScreenInit", + "DRIDestroyInfoRec", + "DRICloseScreen", + "DRIDestroyInfoRec", + "DRIScreenInit", + "DRIDestroyInfoRec", + "DRICreateInfoRec", + "DRILock", + "DRIUnlock", + "DRIGetSAREAPrivate", + "DRIGetContext", + "GlxSetVisualConfigs", + NULL +}; +#endif + static MODULESETUPPROTO(R128Setup); static XF86ModuleVersionInfo R128VersRec = @@ -347,6 +416,10 @@ static pointer R128Setup(pointer module, pointer opts, int *errmaj, xaaSymbols, xf8_32bppSymbols, ramdacSymbols, +#ifdef XF86DRI + drmSymbols, + driSymbols, +#endif fbdevHWSymbols, vbeSymbols, 0 /* ddcsymbols */, @@ -518,7 +591,7 @@ static void R128Unblank(ScrnInfoPtr pScrn) } /* Compute log base 2 of val. */ -static int R128MinBits(int val) +int R128MinBits(int val) { int bits; @@ -779,6 +852,7 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn) int offset = 0; /* RAM Type */ MessageType from; unsigned char *R128MMIO; + /* Chipset */ from = X_PROBED; if (dev->chipset && *dev->chipset) { @@ -876,7 +950,7 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn) switch (info->MemCntl & 0x3) { case 0: /* SDR SGRAM 1:1 */ switch (info->Chipset) { - case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RE: case PCI_CHIP_RAGE128RF: offset = 0; break; /* 128-bit SDR SGRAM 1:1 */ case PCI_CHIP_RAGE128RK: case PCI_CHIP_RAGE128RL: @@ -895,12 +969,28 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn) pScrn->videoRam); from = X_CONFIG; pScrn->videoRam = dev->videoRam; - } + } pScrn->videoRam &= ~1023; info->FbMapSize = pScrn->videoRam * 1024; xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte (%s)\n", pScrn->videoRam, info->ram->name); +#ifdef XF86DRI + /* AGP/PCI */ + if (xf86ReturnOptValBool(R128Options, OPTION_IS_PCI, FALSE)) { + info->IsPCI = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI-only mode\n"); + } else { + switch (info->Chipset) { + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RK: info->IsPCI = TRUE; break; + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RL: + case PCI_CHIP_RAGE128PF: + default: info->IsPCI = FALSE; break; + } + } +#endif return TRUE; } @@ -1053,6 +1143,143 @@ static Bool R128PreInitInt10(ScrnInfoPtr pScrn) return TRUE; } +#ifdef XF86DRI +static Bool R128PreInitDRI(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (info->IsPCI) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "CCE in PIO mode\n"); + info->CCEMode = R128_DEFAULT_CCE_PIO_MODE; + } else if (xf86ReturnOptValBool(R128Options, OPTION_CCE_PIO, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "CCE in PIO mode\n"); + info->CCEMode = R128_DEFAULT_CCE_PIO_MODE; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "CCE in BM mode\n"); + info->CCEMode = R128_DEFAULT_CCE_BM_MODE; + } + + if (xf86ReturnOptValBool(R128Options, OPTION_USE_CCE_2D, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using CCE for 2D\n"); + info->CCE2D = TRUE; + } else { + info->CCE2D = FALSE; + } + + if (xf86ReturnOptValBool(R128Options, OPTION_NO_SECURITY, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "WARNING!!! CCE Security checks disabled!!! **********\n"); + info->CCESecure = FALSE; + } else { + info->CCESecure = TRUE; + } + + info->agpMode = R128_DEFAULT_AGP_MODE; + info->agpSize = R128_DEFAULT_AGP_SIZE; + info->ringSize = R128_DEFAULT_RING_SIZE; + info->vbSize = R128_DEFAULT_VB_SIZE; + info->indSize = R128_DEFAULT_IND_SIZE; + info->agpTexSize = R128_DEFAULT_AGP_TEX_SIZE; + + info->vbBufSize = R128_DEFAULT_VB_BUF_SIZE; + + info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT; + + if (!info->IsPCI) { + if (xf86GetOptValInteger(R128Options, + OPTION_AGP_MODE, &(info->agpMode))) { + if (info->agpMode < 1 || info->agpMode > R128_AGP_MAX_MODE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal AGP Mode: %d\n", info->agpMode); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using AGP %dx mode\n", info->agpMode); + } + + if (xf86GetOptValInteger(R128Options, + OPTION_AGP_SIZE, (int *)&(info->agpSize))) { + switch (info->agpSize) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal AGP size: %d MB\n", info->agpSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(R128Options, + OPTION_RING_SIZE, &(info->ringSize))) { + if (info->ringSize < 1 || info->ringSize >= info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal ring buffer size: %d MB\n", + info->ringSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(R128Options, + OPTION_VERT_SIZE, &(info->vbSize))) { + if (info->vbSize < 1 || info->vbSize >= info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal vertex buffers list size: %d MB\n", + info->vbSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(R128Options, + OPTION_VBUF_SIZE, &(info->vbBufSize))) { + int numBufs = info->vbSize*1024*1024/info->vbBufSize; + if (numBufs < 2 || numBufs > 512) { /* FIXME: 512 is arbitrary */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal individual vertex buffer size: %d bytes\n", + info->vbBufSize); + return FALSE; + } + } + + if (info->ringSize + info->vbSize + info->indSize + info->agpTexSize > + info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Buffers are too big for requested AGP space\n"); + return FALSE; + } + + info->agpTexSize = info->agpSize - (info->ringSize + + info->vbSize + + info->indSize); + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d MB AGP aperture\n", info->agpSize); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d MB for the ring buffer\n", info->ringSize); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d MB for vertex buffers\n", info->vbSize); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d MB for indirect buffers\n", info->indSize); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d MB for AGP textures\n", info->agpTexSize); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using %d byte vertex buffers\n", info->vbBufSize); + } + + if (xf86GetOptValInteger(R128Options, OPTION_USEC_TIMEOUT, + &(info->CCEusecTimeout))) { + /* This option checked by the R128 DRM kernel module */ + } + + return TRUE; +} +#endif + extern xf86MonPtr ConfiguredMonitor; static void @@ -1152,6 +1379,10 @@ static Bool R128PreInit(ScrnInfoPtr pScrn, int flags) if (!R128PreInitAccel(pScrn)) goto fail; +#ifdef XF86DRI + if (!R128PreInitDRI(pScrn)) goto fail; +#endif + return TRUE; fail: @@ -1231,9 +1462,20 @@ static Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, R128TRACE(("R128ScreenInit %x %d\n", pScrn->memPhysBase, pScrn->fbOffset)); +#ifdef XF86DRI + /* Turn off the CCE for now. */ + info->CCEInUse = FALSE; +#endif + if (!R128MapMem(pScrn)) return FALSE; pScrn->fbOffset = 0; - +#ifdef XF86DRI + info->fbX = 0; + info->fbY = 0; +#endif + + info->PaletteSavedOnVT = FALSE; + R128Save(pScrn); if (info->FBDev) { if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE; @@ -1251,6 +1493,18 @@ static Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; +#ifdef XF86DRI + /* Setup DRI after visuals have been + established, but before cfbScreenInit is + called. cfbScreenInit will eventually + call the driver's InitGLXVisuals call + back. */ + if (!xf86ReturnOptValBool(R128Options, OPTION_NOACCEL, FALSE)) + info->directRenderingEnabled = R128DRIScreenInit(pScreen); + else + info->directRenderingEnabled = FALSE; +#endif + #ifdef USE_FB if (!fbScreenInit (pScreen, info->FB, pScrn->virtualX, pScrn->virtualY, @@ -1358,6 +1612,101 @@ static Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, } } +#ifdef XF86DRI + /* Allocate frame buffer space for the + shared back and depth buffers as well + as for local textures. */ + if (info->directRenderingEnabled) { + FBAreaPtr fbarea; + int width_bytes = pScrn->displayWidth * info->pixel_bytes; + int maxy = info->FbMapSize / width_bytes; + int l; + + /* Allocate the shared back buffer */ + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY, + 32, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved back buffer from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + + info->backX = fbarea->box.x1; + info->backY = fbarea->box.y1; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve back buffer\n"); + info->backX = -1; + info->backY = -1; + } + + /* Allocate the shared depth buffer */ + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY, + 32, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved depth buffer from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + + info->depthX = fbarea->box.x1; + info->depthY = fbarea->box.y1; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve depth buffer\n"); + info->depthX = -1; + info->depthY = -1; + } + + /* Allocate local texture space */ + if (((maxy - MemBox.y2 - 1) * width_bytes) > + (pScrn->virtualX * pScrn->virtualY * 2 * info->pixel_bytes)) { + info->textureX = 0; + info->textureY = MemBox.y2 + 1; + info->textureSize = (maxy - MemBox.y2 - 1) * width_bytes; + + l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + + info->log2TexGran = l; + info->textureSize = (info->textureSize >> l) << l; + + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved %d kb for textures: (%d,%d)-(%d,%d)\n", + info->textureSize/1024, + info->textureX, info->textureY, + pScrn->displayWidth, maxy); + } else if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY * 2, + 32, + NULL, NULL, NULL))) { + info->textureX = fbarea->box.x1; + info->textureY = fbarea->box.y1; + info->textureSize = ((fbarea->box.y2 - fbarea->box.y1) * + (fbarea->box.x2 - fbarea->box.x1) * + info->pixel_bytes); + + l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + + info->log2TexGran = l; + info->textureSize = (info->textureSize >> l) << l; + + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved %d kb for textures: (%d,%d)-(%d,%d)\n", + info->textureSize/1024, + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Unable to reserve texture space in frame buffer\n"); + info->textureX = -1; + info->textureY = -1; + } + } +#endif + /* Backing store setup */ miInitializeBackingStore(pScreen); xf86SetBackingStore(pScreen); @@ -1453,6 +1802,21 @@ static Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); +#ifdef XF86DRI + /* DRI finalization */ + if (info->directRenderingEnabled) { + /* Now that mi, cfb, drm and others have + done their thing, complete the DRI + setup. */ + info->directRenderingEnabled = R128DRIFinishScreenInit(pScreen); + } + if (info->directRenderingEnabled) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering disabled\n"); + } +#endif + return TRUE; } @@ -1473,7 +1837,7 @@ static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) OUTREG(R128_GEN_INT_CNTL, restore->gen_int_cntl); OUTREG(R128_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); OUTREG(R128_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); - OUTREG(R128_BUS_CNTL, restore->bus_cntl); + OUTREG(R128_BUS_CNTL, restore->bus_cntl); } /* Write CRTC registers. */ @@ -1603,7 +1967,7 @@ static void R128SaveCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr save) save->gen_int_cntl = INREG(R128_GEN_INT_CNTL); save->cap0_trig_cntl = INREG(R128_CAP0_TRIG_CNTL); save->cap1_trig_cntl = INREG(R128_CAP1_TRIG_CNTL); - save->bus_cntl = INREG(R128_BUS_CNTL); + save->bus_cntl = INREG(R128_BUS_CNTL); } /* Read CRTC registers. */ @@ -2025,7 +2389,7 @@ static Bool R128Init(ScrnInfoPtr pScrn, DisplayModePtr mode, R128SavePtr save) R128InitPLLRegisters(pScrn, save, mode, &info->pll, dot_clock); if (!R128InitDDARegisters(pScrn, save, mode, &info->pll, info)) return FALSE; - R128InitPalette(save, info); + if (!info->PaletteSavedOnVT) R128InitPalette(save, info); R128TRACE(("R128Init returns %p\n", save)); return TRUE; @@ -2037,6 +2401,7 @@ static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) R128InfoPtr info = R128PTR(pScrn); if (!R128Init(pScrn, mode, &info->ModeReg)) return FALSE; + /* FIXME? DRILock/DRIUnlock here? */ R128Blank(pScrn); R128RestoreMode(pScrn, &info->ModeReg); R128Unblank(pScrn); @@ -2096,14 +2461,43 @@ static void R128AdjustFrame(int scrnIndex, int x, int y, int flags) mode. */ static Bool R128EnterVT(int scrnIndex, int flags) { - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); R128TRACE(("R128EnterVT\n")); +#ifdef XF86DRI + if (R128PTR(pScrn)->directRenderingEnabled) { + R128CCEStart(pScrn); + DRIUnlock(pScrn->pScreen); + } +#endif if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE; + info->PaletteSavedOnVT = FALSE; R128AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; } +/* Called when VT switching away from the X server. Restore the original + text mode. */ +static void R128LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + R128SavePtr save = &info->ModeReg; + + R128TRACE(("R128LeaveVT\n")); +#ifdef XF86DRI + if (R128PTR(pScrn)->directRenderingEnabled) { + DRILock(pScrn->pScreen, 0); + R128CCEStop(pScrn); + } +#endif + R128SavePalette(pScrn, save); + info->PaletteSavedOnVT = TRUE; + R128Restore(pScrn); +} + static Bool R128EnterVTFBDev(int scrnIndex, int flags) { @@ -2116,8 +2510,6 @@ R128EnterVTFBDev(int scrnIndex, int flags) return TRUE; } -/* Called when VT switching away from the X server. Restore the original - text mode. */ static void R128LeaveVTFBDev(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; @@ -2127,14 +2519,6 @@ static void R128LeaveVTFBDev(int scrnIndex, int flags) fbdevHWLeaveVT(scrnIndex,flags); } -static void R128LeaveVT(int scrnIndex, int flags) -{ - ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - - R128TRACE(("R128LeaveVT\n")); - R128Restore(pScrn); -} - /* Called at the end of each server generation. Restore the original text mode, unmap video memory, and unwrap and call the saved CloseScreen function. */ @@ -2144,6 +2528,15 @@ static Bool R128CloseScreen(int scrnIndex, ScreenPtr pScreen) R128InfoPtr info = R128PTR(pScrn); R128TRACE(("R128CloseScreen\n")); + +#ifdef XF86DRI + /* Disable direct rendering */ + if (info->directRenderingEnabled) { + R128DRICloseScreen(pScreen); + info->directRenderingEnabled = FALSE; + } +#endif + if (pScrn->vtSema) { R128Restore(pScrn); R128UnmapMem(pScrn); diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_reg.h b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_reg.h index 86652affa..144fd9efe 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_reg.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_reg.h @@ -1,8 +1,8 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/r128/r128_reg.h,v 1.6 2000/02/23 04:47:19 martin Exp $ */ /************************************************************************** -Copyright 1999 ATI Technologies Inc. and Precision Insight, Inc., - Cedar Park, Texas. +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a @@ -159,9 +159,20 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_AGP_APER_OFFSET 0x0178 #define R128_AGP_BASE 0x0170 #define R128_AGP_CNTL 0x0174 +# define R128_AGP_APER_SIZE_256MB (0x00 << 0) +# define R128_AGP_APER_SIZE_128MB (0x20 << 0) +# define R128_AGP_APER_SIZE_64MB (0x30 << 0) +# define R128_AGP_APER_SIZE_32MB (0x38 << 0) +# define R128_AGP_APER_SIZE_16MB (0x3c << 0) +# define R128_AGP_APER_SIZE_8MB (0x3e << 0) +# define R128_AGP_APER_SIZE_4MB (0x3f << 0) +# define R128_AGP_APER_SIZE_MASK (0x3f << 0) #define R128_AGP_COMMAND 0x0f58 /* PCI */ #define R128_AGP_PLL_CNTL 0x0010 /* PLL */ #define R128_AGP_STATUS 0x0f54 /* PCI */ +# define R128_AGP_1X_MODE 0x01 +# define R128_AGP_2X_MODE 0x02 +# define R128_AGP_MODE_MASK 0x03 #define R128_AMCGPIO_A_REG 0x01a0 #define R128_AMCGPIO_EN_REG 0x01a8 #define R128_AMCGPIO_MASK 0x0194 @@ -169,6 +180,15 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_ATTRDR 0x03c1 /* VGA */ #define R128_ATTRDW 0x03c0 /* VGA */ #define R128_ATTRX 0x03c0 /* VGA */ +# define R128_AUX1_SC_EN (1 << 0) +# define R128_AUX1_SC_MODE_OR (0 << 1) +# define R128_AUX1_SC_MODE_NAND (1 << 1) +# define R128_AUX2_SC_EN (1 << 2) +# define R128_AUX2_SC_MODE_OR (0 << 3) +# define R128_AUX2_SC_MODE_NAND (1 << 3) +# define R128_AUX3_SC_EN (1 << 4) +# define R128_AUX3_SC_MODE_OR (0 << 5) +# define R128_AUX3_SC_MODE_NAND (1 << 5) #define R128_AUX_SC_CNTL 0x1660 #define R128_AUX1_SC_BOTTOM 0x1670 #define R128_AUX1_SC_LEFT 0x1664 @@ -257,11 +277,12 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_BRUSH_SCALE 0x1470 #define R128_BRUSH_Y_X 0x1474 #define R128_BUS_CNTL 0x0030 -# define R128_BUS_RD_DISCARD_EN (1 << 24) -# define R128_BUS_RD_ABORT_EN (1 << 25) -# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28) -# define R128_BUS_WRT_BURST (1 << 29) -# define R128_BUS_READ_BURST (1 << 30) +# define R128_BUS_MASTER_DIS (1 << 6) +# define R128_BUS_RD_DISCARD_EN (1 << 24) +# define R128_BUS_RD_ABORT_EN (1 << 25) +# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define R128_BUS_WRT_BURST (1 << 29) +# define R128_BUS_READ_BURST (1 << 30) #define R128_BUS_CNTL1 0x0034 #define R128_CACHE_CNTL 0x1724 @@ -297,6 +318,9 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_CONFIG_REG_APER_SIZE 0x0110 #define R128_CONFIG_XSTRAP 0x00e4 #define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_COLOR_MASK 0x00ffffff +# define R128_CONSTANT_COLOR_ONE 0x00ffffff +# define R128_CONSTANT_COLOR_ZERO 0x00000000 #define R128_CRC_CMDFIFO_ADDR 0x0740 #define R128_CRC_CMDFIFO_DOUT 0x0744 #define R128_CRTC_CRNT_FRAME 0x0214 @@ -360,8 +384,13 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 # define R128_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) # define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) -#define R128_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define R128_FOG_3D_TABLE_START 0x1810 +#define R128_FOG_3D_TABLE_END 0x1814 +#define R128_FOG_3D_TABLE_DENSITY 0x181c +#define R128_FOG_TABLE_INDEX 0x1a14 +#define R128_FOG_TABLE_DATA 0x1a18 #define R128_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define R128_DESTINATION_3D_CLR_CMP_MSK 0x1824 #define R128_DEVICE_ID 0x0f02 /* PCI */ #define R128_DP_BRUSH_BKGD_CLR 0x1478 #define R128_DP_BRUSH_FRGD_CLR 0x147c @@ -373,6 +402,7 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l # define R128_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) # define R128_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) #define R128_DP_DATATYPE 0x16c4 +# define R128_HOST_BIG_ENDIAN_EN (1 << 29) #define R128_DP_GUI_MASTER_CNTL 0x146c # define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) # define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) @@ -388,6 +418,19 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l # define R128_GMC_BRUSH_8x8_COLOR (10 << 4) # define R128_GMC_BRUSH_1X8_COLOR (12 << 4) # define R128_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define R128_GMC_BRUSH_NONE (15 << 4) +# define R128_GMC_DST_8BPP_CI (2 << 8) +# define R128_GMC_DST_15BPP (3 << 8) +# define R128_GMC_DST_16BPP (4 << 8) +# define R128_GMC_DST_24BPP (5 << 8) +# define R128_GMC_DST_32BPP (6 << 8) +# define R128_GMC_DST_8BPP_RGB (7 << 8) +# define R128_GMC_DST_Y8 (8 << 8) +# define R128_GMC_DST_RGB8 (9 << 8) +# define R128_GMC_DST_VYUY (11 << 8) +# define R128_GMC_DST_YVYU (12 << 8) +# define R128_GMC_DST_AYUV444 (14 << 8) +# define R128_GMC_DST_ARGB4444 (15 << 8) # define R128_GMC_DST_DATATYPE_MASK (0x0f << 8) # define R128_GMC_DST_DATATYPE_SHIFT 8 # define R128_GMC_SRC_DATATYPE_MASK (3 << 12) @@ -395,8 +438,11 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l # define R128_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) # define R128_GMC_SRC_DATATYPE_COLOR (3 << 12) # define R128_GMC_BYTE_PIX_ORDER (1 << 14) +# define R128_GMC_BYTE_MSB_TO_LSB (0 << 14) # define R128_GMC_BYTE_LSB_TO_MSB (1 << 14) # define R128_GMC_CONVERSION_TEMP (1 << 15) +# define R128_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define R128_GMC_CONVERSION_TEMP_9300 (1 << 15) # define R128_GMC_ROP3_MASK (0xff << 16) # define R128_DP_SRC_SOURCE_MASK (7 << 24) # define R128_DP_SRC_SOURCE_MEMORY (2 << 24) @@ -404,7 +450,7 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l # define R128_GMC_3D_FCN_EN (1 << 27) # define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28) # define R128_AUX_CLIP_DIS (1 << 29) -# define R128_GMC_WR_MSK_DS (1 << 30) +# define R128_GMC_WR_MSK_DIS (1 << 30) # define R128_GMC_LD_BRUSH_Y_X (1 << 31) # define R128_ROP3_ZERO 0x00000000 # define R128_ROP3_DSa 0x00880000 @@ -456,6 +502,7 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_DST_PITCH 0x1408 #define R128_DST_PITCH_OFFSET 0x142c #define R128_DST_PITCH_OFFSET_C 0x1c80 +# define R128_PITCH_SHIFT 21 #define R128_DST_WIDTH 0x140c #define R128_DST_WIDTH_HEIGHT 0x1598 #define R128_DST_WIDTH_X 0x1588 @@ -573,7 +620,6 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_MEM_VGA_RP_SEL 0x003c #define R128_MEM_VGA_WP_SEL 0x0038 #define R128_MIN_GRANT 0x0f3e /* PCI */ -#define R128_MISC_3D_STATE_CNTL_REG 0x1CA0 #define R128_MM_DATA 0x0004 #define R128_MM_INDEX 0x0000 #define R128_MPLL_CNTL 0x000e /* PLL */ @@ -592,7 +638,10 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_PC_DEBUG_MODE 0x1760 #define R128_PC_GUI_CTLSTAT 0x1748 #define R128_PC_GUI_MODE 0x1744 +# define R128_PC_IGNORE_UNIFY (1 << 5) #define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_GUI (3 << 0) +# define R128_PC_RI_GUI (1 << 2) # define R128_PC_FLUSH_ALL 0x00ff # define R128_PC_BUSY (1 << 31) #define R128_PC_NGUI_MODE 0x0180 @@ -689,6 +738,538 @@ static inline unsigned short regr16(volatile unsigned long base_addr, unsigned l #define R128_XDLL_CNTL 0x000c /* PLL */ #define R128_XPLL_CNTL 0x000b /* PLL */ + /* Registers for CCE and Microcode Engine */ +#define R128_PM4_MICROCODE_ADDR 0x07d4 +#define R128_PM4_MICROCODE_RADDR 0x07d8 +#define R128_PM4_MICROCODE_DATAH 0x07dc +#define R128_PM4_MICROCODE_DATAL 0x07e0 + +#define R128_PM4_BUFFER_OFFSET 0x0700 +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) +#define R128_PM4_BUFFER_WM_CNTL 0x0708 +# define R128_WMA_SHIFT 0 +# define R128_WMB_SHIFT 8 +# define R128_WMC_SHIFT 16 +# define R128_WB_WM_SHIFT 24 +#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) +#define R128_PM4_VC_FPU_SETUP 0x071c +# define R128_FRONT_DIR_CW (0 << 0) +# define R128_FRONT_DIR_CCW (1 << 0) +# define R128_FRONT_DIR_MASK (1 << 0) +# define R128_BACKFACE_CULL (0 << 1) +# define R128_BACKFACE_POINTS (1 << 1) +# define R128_BACKFACE_LINES (2 << 1) +# define R128_BACKFACE_SOLID (3 << 1) +# define R128_BACKFACE_MASK (3 << 1) +# define R128_FRONTFACE_CULL (0 << 3) +# define R128_FRONTFACE_POINTS (1 << 3) +# define R128_FRONTFACE_LINES (2 << 3) +# define R128_FRONTFACE_SOLID (3 << 3) +# define R128_FRONTFACE_MASK (3 << 3) +# define R128_FPU_COLOR_SOLID (0 << 5) +# define R128_FPU_COLOR_FLAT (1 << 5) +# define R128_FPU_COLOR_GOURAUD (2 << 5) +# define R128_FPU_COLOR_GOURAUD2 (3 << 5) +# define R128_FPU_SUB_PIX_2BITS (0 << 7) +# define R128_FPU_SUB_PIX_4BITS (1 << 7) +# define R128_FPU_MODE_2D (0 << 8) +# define R128_FPU_MODE_3D (1 << 8) +# define R128_TRAP_BITS_DISABLE (1 << 9) +# define R128_EDGE_ANTIALIAS (1 << 10) +# define R128_SUPERSAMPLE (1 << 11) +# define R128_XFACTOR_2 (0 << 12) +# define R128_XFACTOR_4 (1 << 12) +# define R128_YFACTOR_2 (0 << 13) +# define R128_YFACTOR_4 (1 << 13) +# define R128_FLAT_SHADE_VERTEX_D3D (0 << 14) +# define R128_FLAT_SHADE_VERTEX_OGL (1 << 14) +# define R128_FPU_ROUND_TRUNCATE (0 << 15) +# define R128_FPU_ROUND_NEAREST (1 << 15) +# define R128_WM_SEL_8DW (0 << 16) +# define R128_WM_SEL_16DW (1 << 16) +# define R128_WM_SEL_32DW (2 << 16) +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + #define R128_SCALE_3D_CNTL 0x1a00 +# define R128_SCALE_DITHER_ERR_DIFF (0 << 1) +# define R128_SCALE_DITHER_TABLE (1 << 1) +# define R128_TEX_CACHE_SIZE_FULL (0 << 2) +# define R128_TEX_CACHE_SIZE_HALF (1 << 2) +# define R128_DITHER_INIT_CURR (0 << 3) +# define R128_DITHER_INIT_RESET (1 << 3) +# define R128_ROUND_24BIT (1 << 4) +# define R128_TEX_CACHE_DISABLE (1 << 5) +# define R128_SCALE_3D_NOOP (0 << 6) +# define R128_SCALE_3D_SCALE (1 << 6) +# define R128_SCALE_3D_TEXMAP_SHADE (2 << 6) +# define R128_SCALE_PIX_BLEND (0 << 8) +# define R128_SCALE_PIX_REPLICATE (1 << 8) +# define R128_TEX_CACHE_SPLIT (1 << 9) +# define R128_APPLE_YUV_MODE (1 << 10) +# define R128_TEX_CACHE_PALLETE_MODE (1 << 11) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NCLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_NCLAMP (3 << 12) +# define R128_FOG_TABLE (1 << 14) +# define R128_SIGNED_DST_CLAMP (1 << 15) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DSTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DSTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BLEND (11 << 16) +# define R128_ALPHA_BLEND_SRC_INVBLEND (12 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DSTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DSTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTCOLOR (9 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_COMPOSITE_SHADOW_CMP_EQUAL (0 << 28) +# define R128_COMPOSITE_SHADOW_CMP_NEQUAL (1 << 28) +# define R128_COMPOSITE_SHADOW (1 << 29) +# define R128_TEX_MAP_ALPHA_IN_TEXTURE (1 << 30) +# define R128_TEX_CACHE_LINE_SIZE_8QW (0 << 31) +# define R128_TEX_CACHE_LINE_SIZE_4QW (1 << 31) + +#define R128_SETUP_CNTL 0x1bc4 +# define R128_DONT_START_TRIANGLE (1 << 0) +# define R128_Z_BIAS (0 << 1) +# define R128_DONT_START_ANY_ON (1 << 2) +# define R128_COLOR_SOLID_COLOR (0 << 3) +# define R128_COLOR_FLAT_VERT_1 (1 << 3) +# define R128_COLOR_FLAT_VERT_2 (2 << 3) +# define R128_COLOR_FLAT_VERT_3 (3 << 3) +# define R128_COLOR_GOURAUD (4 << 3) +# define R128_PRIM_TYPE_TRI (0 << 7) +# define R128_PRIM_TYPE_LINE (1 << 7) +# define R128_PRIM_TYPE_POINT (2 << 7) +# define R128_PRIM_TYPE_POLY_EDGE (3 << 7) +# define R128_TEXTURE_ST_MULT_W (0 << 9) +# define R128_TEXTURE_ST_DIRECT (1 << 9) +# define R128_STARTING_VERTEX_1 (1 << 14) +# define R128_STARTING_VERTEX_2 (2 << 14) +# define R128_STARTING_VERTEX_3 (3 << 14) +# define R128_ENDING_VERTEX_1 (1 << 16) +# define R128_ENDING_VERTEX_2 (2 << 16) +# define R128_ENDING_VERTEX_3 (3 << 16) +# define R128_SU_POLY_LINE_LAST (0 << 18) +# define R128_SU_POLY_LINE_NOT_LAST (1 << 18) +# define R128_SUB_PIX_2BITS (0 << 19) +# define R128_SUB_PIX_4BITS (1 << 19) +# define R128_SET_UP_CONTINUE (1 << 31) + +#define R128_WINDOW_XY_OFFSET 0x1bcc +# define R128_WINDOW_Y_SHIFT 4 +# define R128_WINDOW_X_SHIFT 20 + +#define R128_Z_OFFSET_C 0x1c90 +#define R128_Z_PITCH_C 0x1c94 +#define R128_Z_STEN_CNTL_C 0x1c98 +# define R128_Z_PIX_WIDTH_16 (0 << 1) +# define R128_Z_PIX_WIDTH_24 (1 << 1) +# define R128_Z_PIX_WIDTH_32 (2 << 1) +# define R128_Z_PIX_WIDTH_MASK (3 << 1) +# define R128_Z_TEST_NEVER (0 << 4) +# define R128_Z_TEST_LESS (1 << 4) +# define R128_Z_TEST_LESSEQUAL (2 << 4) +# define R128_Z_TEST_EQUAL (3 << 4) +# define R128_Z_TEST_GREATEREQUAL (4 << 4) +# define R128_Z_TEST_GREATER (5 << 4) +# define R128_Z_TEST_NEQUAL (6 << 4) +# define R128_Z_TEST_ALWAYS (7 << 4) +# define R128_Z_TEST_MASK (7 << 4) +# define R128_STENCIL_TEST_NEVER (0 << 12) +# define R128_STENCIL_TEST_LESS (1 << 12) +# define R128_STENCIL_TEST_LESSEQUAL (2 << 12) +# define R128_STENCIL_TEST_EQUAL (3 << 12) +# define R128_STENCIL_TEST_GREATEREQUAL (4 << 12) +# define R128_STENCIL_TEST_GREATER (5 << 12) +# define R128_STENCIL_TEST_NEQUAL (6 << 12) +# define R128_STENCIL_TEST_ALWAYS (7 << 12) +# define R128_STENCIL_S_FAIL_KEEP (0 << 16) +# define R128_STENCIL_S_FAIL_ZERO (1 << 16) +# define R128_STENCIL_S_FAIL_REPLACE (2 << 16) +# define R128_STENCIL_S_FAIL_INC (3 << 16) +# define R128_STENCIL_S_FAIL_DEC (4 << 16) +# define R128_STENCIL_S_FAIL_INV (5 << 16) +# define R128_STENCIL_ZPASS_KEEP (0 << 20) +# define R128_STENCIL_ZPASS_ZERO (1 << 20) +# define R128_STENCIL_ZPASS_REPLACE (2 << 20) +# define R128_STENCIL_ZPASS_INC (3 << 20) +# define R128_STENCIL_ZPASS_DEC (4 << 20) +# define R128_STENCIL_ZPASS_INV (5 << 20) +# define R128_STENCIL_ZFAIL_KEEP (0 << 24) +# define R128_STENCIL_ZFAIL_ZERO (1 << 24) +# define R128_STENCIL_ZFAIL_REPLACE (2 << 24) +# define R128_STENCIL_ZFAIL_INC (3 << 24) +# define R128_STENCIL_ZFAIL_DEC (4 << 24) +# define R128_STENCIL_ZFAIL_INV (5 << 24) +#define R128_TEX_CNTL_C 0x1c9c +# define R128_Z_ENABLE (1 << 0) +# define R128_Z_WRITE_ENABLE (1 << 1) +# define R128_STENCIL_ENABLE (1 << 3) +# define R128_SHADE_ENABLE (0 << 4) +# define R128_TEXMAP_ENABLE (1 << 4) +# define R128_SEC_TEXMAP_ENABLE (1 << 5) +# define R128_FOG_ENABLE (1 << 7) +# define R128_DITHER_ENABLE (1 << 8) +# define R128_ALPHA_ENABLE (1 << 9) +# define R128_ALPHA_TEST_ENABLE (1 << 10) +# define R128_SPEC_LIGHT_ENABLE (1 << 11) +# define R128_TEX_CHROMA_KEY_ENABLE (1 << 12) +# define R128_ALPHA_IN_TEX_COMPLETE_A (0 << 13) +# define R128_ALPHA_IN_TEX_LSB_A (1 << 13) +# define R128_LIGHT_DIS (0 << 14) +# define R128_LIGHT_COPY (1 << 14) +# define R128_LIGHT_MODULATE (2 << 14) +# define R128_LIGHT_ADD (3 << 14) +# define R128_LIGHT_BLEND_CONSTANT (4 << 14) +# define R128_LIGHT_BLEND_TEXTURE (5 << 14) +# define R128_LIGHT_BLEND_VERTEX (6 << 14) +# define R128_LIGHT_BLEND_CONST_COLOR (7 << 14) +# define R128_ALPHA_LIGHT_DIS (0 << 18) +# define R128_ALPHA_LIGHT_COPY (1 << 18) +# define R128_ALPHA_LIGHT_MODULATE (2 << 18) +# define R128_ALPHA_LIGHT_ADD (3 << 18) +# define R128_ANTI_ALIAS (1 << 21) +# define R128_TEX_CACHE_FLUSH (1 << 23) +# define R128_LOD_BIAS_SHIFT 24 +#define R128_MISC_3D_STATE_CNTL_REG 0x1ca0 +# define R128_REF_ALPHA_MASK 0xff +# define R128_MISC_SCALE_3D_NOOP (0 << 8) +# define R128_MISC_SCALE_3D_SCALE (1 << 8) +# define R128_MISC_SCALE_3D_TEXMAP_SHADE (2 << 8) +# define R128_MISC_SCALE_PIX_BLEND (0 << 10) +# define R128_MISC_SCALE_PIX_REPLICATE (1 << 10) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NO_CLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_NO_CLAMP (3 << 12) +# define R128_FOG_VERTEX (0 << 14) +# define R128_FOG_TABLE (1 << 14) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DESTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DESTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHASAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHSRCALPHA (11 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHINVSRCALPHA (12 << 16) +# define R128_ALPHA_BLEND_SRC_MASK (15 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DESTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DESTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTCOLOR (9 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHASAT (10 << 20) +# define R128_ALPHA_BLEND_DST_MASK (15 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_ALPHA_TEST_MASK (7 << 24) +#define R128_TEXTURE_CLR_CMP_CLR_C 0x1ca4 +#define R128_TEXTURE_CLR_CMP_MSK_C 0x1ca8 +#define R128_FOG_COLOR_C 0x1cac +# define R128_FOG_BLUE_SHIFT 0 +# define R128_FOG_GREEN_SHIFT 8 +# define R128_FOG_RED_SHIFT 16 +#define R128_PRIM_TEX_CNTL_C 0x1cb0 +# define R128_MIN_BLEND_NEAREST (0 << 1) +# define R128_MIN_BLEND_LINEAR (1 << 1) +# define R128_MIN_BLEND_MIPNEAREST (2 << 1) +# define R128_MIN_BLEND_MIPLINEAR (3 << 1) +# define R128_MIN_BLEND_LINEARMIPNEAREST (4 << 1) +# define R128_MIN_BLEND_LINEARMIPLINEAR (5 << 1) +# define R128_MIN_BLEND_MASK (7 << 1) +# define R128_MAG_BLEND_NEAREST (0 << 4) +# define R128_MAG_BLEND_LINEAR (1 << 4) +# define R128_MAG_BLEND_MASK (7 << 4) +# define R128_MIP_MAP_DISABLE (1 << 7) +# define R128_TEX_CLAMP_S_WRAP (0 << 8) +# define R128_TEX_CLAMP_S_MIRROR (1 << 8) +# define R128_TEX_CLAMP_S_CLAMP (2 << 8) +# define R128_TEX_CLAMP_S_BORDER_COLOR (3 << 8) +# define R128_TEX_CLAMP_S_MASK (3 << 8) +# define R128_TEX_WRAP_S (1 << 10) +# define R128_TEX_CLAMP_T_WRAP (0 << 11) +# define R128_TEX_CLAMP_T_MIRROR (1 << 11) +# define R128_TEX_CLAMP_T_CLAMP (2 << 11) +# define R128_TEX_CLAMP_T_BORDER_COLOR (3 << 11) +# define R128_TEX_CLAMP_T_MASK (3 << 11) +# define R128_TEX_WRAP_T (1 << 13) +# define R128_TEX_PERSPECTIVE_DISABLE (1 << 14) +# define R128_DATATYPE_VQ (0 << 16) +# define R128_DATATYPE_CI4 (1 << 16) +# define R128_DATATYPE_CI8 (2 << 16) +# define R128_DATATYPE_ARGB1555 (3 << 16) +# define R128_DATATYPE_RGB565 (4 << 16) +# define R128_DATATYPE_RGB888 (5 << 16) +# define R128_DATATYPE_ARGB8888 (6 << 16) +# define R128_DATATYPE_RGB332 (7 << 16) +# define R128_DATATYPE_Y8 (8 << 16) +# define R128_DATATYPE_RGB8 (9 << 16) +# define R128_DATATYPE_CI16 (10 << 16) +# define R128_DATATYPE_YUV422 (11 << 16) +# define R128_DATATYPE_YUV422_2 (12 << 16) +# define R128_DATATYPE_AYUV444 (14 << 16) +# define R128_DATATYPE_ARGB4444 (15 << 16) +# define R128_PALLETE_EITHER (0 << 20) +# define R128_PALLETE_1 (1 << 20) +# define R128_PALLETE_2 (2 << 20) +# define R128_PSEUDOCOLOR_DT_RGB565 (0 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB1555 (1 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB4444 (2 << 24) +#define R128_PRIM_TEXTURE_COMBINE_CNTL_C 0x1cb4 +# define R128_COMB_DIS (0 << 0) +# define R128_COMB_COPY (1 << 0) +# define R128_COMB_COPY_INP (2 << 0) +# define R128_COMB_MODULATE (3 << 0) +# define R128_COMB_MODULATE2X (4 << 0) +# define R128_COMB_MODULATE4X (5 << 0) +# define R128_COMB_ADD (6 << 0) +# define R128_COMB_ADD_SIGNED (7 << 0) +# define R128_COMB_BLEND_VERTEX (8 << 0) +# define R128_COMB_BLEND_TEXTURE (9 << 0) +# define R128_COMB_BLEND_CONST (10 << 0) +# define R128_COMB_BLEND_PREMULT (11 << 0) +# define R128_COMB_BLEND_PREV (12 << 0) +# define R128_COMB_BLEND_PREMULT_INV (13 << 0) +# define R128_COMB_ADD_SIGNED2X (14 << 0) +# define R128_COMB_BLEND_CONST_COLOR (15 << 0) +# define R128_COMB_MASK (15 << 0) +# define R128_COLOR_FACTOR_TEX (4 << 4) +# define R128_COLOR_FACTOR_NTEX (5 << 4) +# define R128_COLOR_FACTOR_ALPHA (6 << 4) +# define R128_COLOR_FACTOR_NALPHA (7 << 4) +# define R128_COLOR_FACTOR_MASK (15 << 4) +# define R128_INPUT_FACTOR_CONST_COLOR (2 << 10) +# define R128_INPUT_FACTOR_CONST_ALPHA (3 << 10) +# define R128_INPUT_FACTOR_INT_COLOR (4 << 10) +# define R128_INPUT_FACTOR_INT_ALPHA (5 << 10) +# define R128_INPUT_FACTOR_MASK (15 << 10) +# define R128_COMB_ALPHA_DIS (0 << 14) +# define R128_COMB_ALPHA_COPY (1 << 14) +# define R128_COMB_ALPHA_COPY_INP (2 << 14) +# define R128_COMB_ALPHA_MODULATE (3 << 14) +# define R128_COMB_ALPHA_MODULATE2X (4 << 14) +# define R128_COMB_ALPHA_MODULATE4X (5 << 14) +# define R128_COMB_ALPHA_ADD (6 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED (7 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED2X (14 << 14) +# define R128_COMB_ALPHA_MASK (15 << 14) +# define R128_ALPHA_FACTOR_TEX_ALPHA (6 << 18) +# define R128_ALPHA_FACTOR_NTEX_ALPHA (7 << 18) +# define R128_ALPHA_FACTOR_MASK (15 << 18) +# define R128_INP_FACTOR_A_CONST_ALPHA (1 << 25) +# define R128_INP_FACTOR_A_INT_ALPHA (2 << 25) +# define R128_INP_FACTOR_A_MASK (7 << 25) +#define R128_TEX_SIZE_PITCH_C 0x1cb8 +# define R128_TEX_PITCH_SHIFT 0 +# define R128_TEX_SIZE_SHIFT 4 +# define R128_TEX_HEIGHT_SHIFT 8 +# define R128_TEX_MIN_SIZE_SHIFT 12 +# define R128_SEC_TEX_PITCH_SHIFT 16 +# define R128_SEC_TEX_SIZE_SHIFT 20 +# define R128_SEC_TEX_HEIGHT_SHIFT 24 +# define R128_SEC_TEX_MIN_SIZE_SHIFT 28 +# define R128_TEX_PITCH_MASK (0x0f << 0) +# define R128_TEX_SIZE_MASK (0x0f << 4) +# define R128_TEX_HEIGHT_MASK (0x0f << 8) +# define R128_TEX_MIN_SIZE_MASK (0x0f << 12) +# define R128_SEC_TEX_PITCH_MASK (0x0f << 16) +# define R128_SEC_TEX_SIZE_MASK (0x0f << 20) +# define R128_SEC_TEX_HEIGHT_MASK (0x0f << 24) +# define R128_SEC_TEX_MIN_SIZE_MASK (0x0f << 28) +# define R128_TEX_SIZE_PITCH_SHIFT 0 +# define R128_SEC_TEX_SIZE_PITCH_SHIFT 16 +# define R128_TEX_SIZE_PITCH_MASK (0xffff << 0) +# define R128_SEC_TEX_SIZE_PITCH_MASK (0xffff << 16) +#define R128_PRIM_TEX_0_OFFSET_C 0x1cbc +#define R128_PRIM_TEX_1_OFFSET_C 0x1cc0 +#define R128_PRIM_TEX_2_OFFSET_C 0x1cc4 +#define R128_PRIM_TEX_3_OFFSET_C 0x1cc8 +#define R128_PRIM_TEX_4_OFFSET_C 0x1ccc +#define R128_PRIM_TEX_5_OFFSET_C 0x1cd0 +#define R128_PRIM_TEX_6_OFFSET_C 0x1cd4 +#define R128_PRIM_TEX_7_OFFSET_C 0x1cd8 +#define R128_PRIM_TEX_8_OFFSET_C 0x1cdc +#define R128_PRIM_TEX_9_OFFSET_C 0x1ce0 +#define R128_PRIM_TEX_10_OFFSET_C 0x1ce4 +# define R128_TEX_NO_TILE (0 << 30) +# define R128_TEX_TILED_BY_HOST (1 << 30) +# define R128_TEX_TILED_BY_STORAGE (2 << 30) +# define R128_TEX_TILED_BY_STORAGE2 (3 << 30) + +#define R128_SEC_TEX_CNTL_C 0x1d00 +# define R128_SEC_SELECT_PRIM_ST (0 << 0) +# define R128_SEC_SELECT_SEC_ST (1 << 0) +#define R128_SEC_TEX_COMBINE_CNTL_C 0x1d04 +# define R128_INPUT_FACTOR_PREV_COLOR (8 << 10) +# define R128_INPUT_FACTOR_PREV_ALPHA (9 << 10) +# define R128_INP_FACTOR_A_PREV_ALPHA (4 << 25) +#define R128_SEC_TEX_0_OFFSET_C 0x1d08 +#define R128_SEC_TEX_1_OFFSET_C 0x1d0c +#define R128_SEC_TEX_2_OFFSET_C 0x1d10 +#define R128_SEC_TEX_3_OFFSET_C 0x1d14 +#define R128_SEC_TEX_4_OFFSET_C 0x1d18 +#define R128_SEC_TEX_5_OFFSET_C 0x1d1c +#define R128_SEC_TEX_6_OFFSET_C 0x1d20 +#define R128_SEC_TEX_7_OFFSET_C 0x1d24 +#define R128_SEC_TEX_8_OFFSET_C 0x1d28 +#define R128_SEC_TEX_9_OFFSET_C 0x1d2c +#define R128_SEC_TEX_10_OFFSET_C 0x1d30 +#define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_BLUE_SHIFT 0 +# define R128_CONSTANT_GREEN_SHIFT 8 +# define R128_CONSTANT_RED_SHIFT 16 +# define R128_CONSTANT_ALPHA_SHIFT 24 +#define R128_PRIM_TEXTURE_BORDER_COLOR_C 0x1d38 +# define R128_PRIM_TEX_BORDER_BLUE_SHIFT 0 +# define R128_PRIM_TEX_BORDER_GREEN_SHIFT 8 +# define R128_PRIM_TEX_BORDER_RED_SHIFT 16 +# define R128_PRIM_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c +# define R128_SEC_TEX_BORDER_BLUE_SHIFT 0 +# define R128_SEC_TEX_BORDER_GREEN_SHIFT 8 +# define R128_SEC_TEX_BORDER_RED_SHIFT 16 +# define R128_SEC_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_STEN_REF_MASK_C 0x1d40 +# define R128_STEN_REFERENCE_SHIFT 0 +# define R128_STEN_MASK_SHIFT 16 +# define R128_STEN_WRITE_MASK_SHIFT 24 +#define R128_PLANE_3D_MASK_C 0x1d44 + + + /* Constants */ +#define R128_AGP_TEX_OFFSET 0x02000000 + +#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 +#define R128_SWAP_AGE_REG R128_GUI_SCRATCH_REG1 + + /* CCE packet types */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET0_ONE_REG_WR 0x00008000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +#define R128_CCE_PACKET3_NOP 0xC0001000 +#define R128_CCE_PACKET3_PAINT 0xC0001100 +#define R128_CCE_PACKET3_BITBLT 0xC0001200 +#define R128_CCE_PACKET3_SMALLTEXT 0xC0001300 +#define R128_CCE_PACKET3_HOSTDATA_BLT 0xC0001400 +#define R128_CCE_PACKET3_POLYLINE 0xC0001500 +#define R128_CCE_PACKET3_SCALING 0xC0001600 +#define R128_CCE_PACKET3_TRANS_SCALING 0xC0001700 +#define R128_CCE_PACKET3_POLYSCANLINES 0xC0001800 +#define R128_CCE_PACKET3_NEXT_CHAR 0xC0001900 +#define R128_CCE_PACKET3_PAINT_MULTI 0xC0001A00 +#define R128_CCE_PACKET3_BITBLT_MULTI 0xC0001B00 +#define R128_CCE_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define R128_CCE_PACKET3_SET_SCISSORS 0xC0001E00 +#define R128_CCE_PACKET3_SET_MODE24BPP 0xC0001F00 +#define R128_CCE_PACKET3_CNTL_PAINT 0xC0009100 +#define R128_CCE_PACKET3_CNTL_BITBLT 0xC0009200 +#define R128_CCE_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define R128_CCE_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define R128_CCE_PACKET3_CNTL_POLYLINE 0xC0009500 +#define R128_CCE_PACKET3_CNTL_SCALING 0xC0009600 +#define R128_CCE_PACKET3_CNTL_TRANS_SCALING 0xC0009700 +#define R128_CCE_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define R128_CCE_PACKET3_CNTL_NEXT_CHAR 0xC0009900 +#define R128_CCE_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define R128_CCE_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define R128_CCE_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 +#define R128_CCE_PACKET3_3D_SAVE_CONTEXT 0xC0002000 +#define R128_CCE_PACKET3_3D_PLAY_CONTEXT 0xC0002100 +#define R128_CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define R128_CCE_PACKET3_3D_RNDR_GEN_PRIM 0xC0002500 +#define R128_CCE_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R128_CCE_PACKET3_PURGE 0xC0002D00 +#define R128_CCE_PACKET3_NEXT_VERTEX_BUNDLE 0xC0002E00 +# define R128_CCE_PACKET_MASK 0xC0000000 +# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +# define R128_CCE_PACKET_MAX_DWORDS (1 << 14) +# define R128_CCE_PACKET0_REG_MASK 0x000007ff +# define R128_CCE_PACKET1_REG0_MASK 0x000007ff +# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + +#define R128_CCE_VC_FRMT_RHW 0x00000001 +#define R128_CCE_VC_FRMT_DIFFUSE_BGR 0x00000002 +#define R128_CCE_VC_FRMT_DIFFUSE_A 0x00000004 +#define R128_CCE_VC_FRMT_DIFFUSE_ARGB 0x00000008 +#define R128_CCE_VC_FRMT_SPEC_BGR 0x00000010 +#define R128_CCE_VC_FRMT_SPEC_F 0x00000020 +#define R128_CCE_VC_FRMT_SPEC_FRGB 0x00000040 +#define R128_CCE_VC_FRMT_S_T 0x00000080 +#define R128_CCE_VC_FRMT_S2_T2 0x00000100 +#define R128_CCE_VC_FRMT_RHW2 0x00000200 + +#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007 +#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define R128_CCE_VC_CNTL_NUM_SHIFT 16 #endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_sarea.h b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_sarea.h new file mode 100644 index 000000000..c5d99df34 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/drivers/r128/r128_sarea.h @@ -0,0 +1,77 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * + */ + +#ifndef _R128_SAREA_H_ +#define _R128_SAREA_H_ + +/* There are 2 heaps (local/AGP). Each region within a heap is a + minimum of 64k, and there are at most 64 of them per heap. */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +typedef struct { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char in_use; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} R128TexRegion; + +typedef struct { + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + /* Last elt is sentinal */ + R128TexRegion texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + /* last time texture was uploaded */ + int texAge[R128_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ + + int ringWrite; /* current ring buffer write index */ +} R128SAREAPriv, *R128SAREAPrivPtr; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/Imakefile b/xc/programs/Xserver/hw/xfree86/os-support/Imakefile index 7041d435a..c42f5b2b7 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/Imakefile +++ b/xc/programs/Xserver/hw/xfree86/os-support/Imakefile @@ -100,6 +100,7 @@ OS_SUBDIR = sco #if BuildXF86DRI && !DoLoadableServer DRM_SRC = $(OS_SUBDIR)/drm/?*.c DRM_OBJ = $(OS_SUBDIR)/drm/?*.o +DRM_DONES = $(OS_SUBDIR)/drm/DONE #endif SUBDIRS = $(OS_SUBDIR) $(BUS_SUBDIR) misc vbe @@ -107,7 +108,7 @@ SUBDIRS = $(OS_SUBDIR) $(BUS_SUBDIR) misc vbe SRCS = $(OS_SUBDIR)/?*.c $(BUS_SUBDIR)/?*.c misc/?*.c vbe/?*.c $(DRM_SRC) OBJS = $(OS_SUBDIR)/?*.o $(BUS_SUBDIR)/?*.o misc/?*.o vbe/?*.o $(DRM_OBJ) -DONES = $(OS_SUBDIR)/DONE $(BUS_SUBDIR)/DONE misc/DONE vbe/DONE +DONES = $(OS_SUBDIR)/DONE $(BUS_SUBDIR)/DONE misc/DONE vbe/DONE $(DRM_DONES) #if HasParallelMake MakeMutex($(SUBDIRS) $(OBJS) $(DONES)) diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/Imakefile b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/Imakefile index 0d413c5c8..4639b530d 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/Imakefile +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/Imakefile @@ -14,8 +14,8 @@ MOBJ = drmmodule.o MTRR_DEFINES = -DHAS_MTRR_SUPPORT #endif -SRCS = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmI810.c xf86drmMga.c $(MSRC) -OBJS = xf86drm.o xf86drmHash.o xf86drmRandom.o xf86drmSL.o xf86drmI810.o xf86drmMga.o $(MOBJ) +SRCS = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmI810.c xf86drmMga.c xf86drmR128.c $(MSRC) +OBJS = xf86drm.o xf86drmHash.o xf86drmRandom.o xf86drmSL.o xf86drmI810.o xf86drmMga.o xf86drmR128.o $(MOBJ) INCLUDES = -I$(XF86COMSRC) -I$(XF86OSSRC) -I. -I$(SERVERSRC)/include \ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm.h index f61a70eb7..9e0ade357 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm.h @@ -69,6 +69,7 @@ typedef struct drm_clip_rect { /* Seperate include files for the i810/mga specific structures */ #include "mga_drm.h" #include "i810_drm.h" +#include "r128_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -341,8 +342,18 @@ typedef struct drm_agp_info { /* I810 specific ioctls */ #define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) #define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) #define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) #define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOWR(0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) + +/* Rage 128 specific ioctls */ +#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) +#define DRM_IOCTL_R128_RESET DRM_IO( 0x41) +#define DRM_IOCTL_R128_FLUSH DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x43) +#define DRM_IOCTL_R128_PACKET DRM_IOW( 0x44, drm_r128_packet_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x45, drm_r128_vertex_t) #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/i810_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/i810_drm.h index 0754874c6..4c8e09f6a 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/i810_drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/i810_drm.h @@ -5,35 +5,112 @@ * if you change them, you must change the defines in the Xserver. */ -/* Might one day want to support the client-side ringbuffer code again. - */ #ifndef _I810_DEFINES_ #define _I810_DEFINES_ -#define I810_USE_BATCH 1 #define I810_DMA_BUF_ORDER 12 #define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER) #define I810_DMA_BUF_NR 256 -#define I810_NR_SAREA_CLIPRECTS 2 +#define I810_NR_SAREA_CLIPRECTS 8 /* Each region is a minimum of 64k, and there are at most 64 of them. */ - #define I810_NR_TEX_REGIONS 64 #define I810_LOG_MIN_TEX_REGION_SIZE 16 #endif +#define I810_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define I810_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define I810_UPLOAD_CTX 0x4 +#define I810_UPLOAD_BUFFERS 0x8 +#define I810_UPLOAD_TEX0 0x10 +#define I810_UPLOAD_TEX1 0x20 +#define I810_UPLOAD_CLIPRECTS 0x40 + + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +/* Destbuffer state + * - backbuffer linear offset and pitch -- invarient in the current dri + * - zbuffer linear offset and pitch -- also invarient + * - drawing origin in back and depth buffers. + * + * Keep the depth/back buffer state here to acommodate private buffers + * in the future. + */ +#define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */ +#define I810_DESTREG_DI1 1 +#define I810_DESTREG_DV0 2 /* GFX_OP_DESTBUFFER_VARS (2 dwords) */ +#define I810_DESTREG_DV1 3 +#define I810_DESTREG_DR0 4 /* GFX_OP_DRAWRECT_INFO (4 dwords) */ +#define I810_DESTREG_DR1 5 +#define I810_DESTREG_DR2 6 +#define I810_DESTREG_DR3 7 +#define I810_DESTREG_DR4 8 +#define I810_DEST_SETUP_SIZE 10 + +/* Context state + */ +#define I810_CTXREG_CF0 0 /* GFX_OP_COLOR_FACTOR */ +#define I810_CTXREG_CF1 1 +#define I810_CTXREG_ST0 2 /* GFX_OP_STIPPLE */ +#define I810_CTXREG_ST1 3 +#define I810_CTXREG_VF 4 /* GFX_OP_VERTEX_FMT */ +#define I810_CTXREG_MT 5 /* GFX_OP_MAP_TEXELS */ +#define I810_CTXREG_MC0 6 /* GFX_OP_MAP_COLOR_STAGES - stage 0 */ +#define I810_CTXREG_MC1 7 /* GFX_OP_MAP_COLOR_STAGES - stage 1 */ +#define I810_CTXREG_MC2 8 /* GFX_OP_MAP_COLOR_STAGES - stage 2 */ +#define I810_CTXREG_MA0 9 /* GFX_OP_MAP_ALPHA_STAGES - stage 0 */ +#define I810_CTXREG_MA1 10 /* GFX_OP_MAP_ALPHA_STAGES - stage 1 */ +#define I810_CTXREG_MA2 11 /* GFX_OP_MAP_ALPHA_STAGES - stage 2 */ +#define I810_CTXREG_SDM 12 /* GFX_OP_SRC_DEST_MONO */ +#define I810_CTXREG_FOG 13 /* GFX_OP_FOG_COLOR */ +#define I810_CTXREG_B1 14 /* GFX_OP_BOOL_1 */ +#define I810_CTXREG_B2 15 /* GFX_OP_BOOL_2 */ +#define I810_CTXREG_LCS 16 /* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */ +#define I810_CTXREG_PV 17 /* GFX_OP_PV_RULE -- Invarient! */ +#define I810_CTXREG_ZA 18 /* GFX_OP_ZBIAS_ALPHAFUNC */ +#define I810_CTXREG_AA 19 /* GFX_OP_ANTIALIAS */ +#define I810_CTX_SETUP_SIZE 20 + +/* Texture state (per tex unit) + */ +#define I810_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (4 dwords) */ +#define I810_TEXREG_MI1 1 +#define I810_TEXREG_MI2 2 +#define I810_TEXREG_MI3 3 +#define I810_TEXREG_MF 4 /* GFX_OP_MAP_FILTER */ +#define I810_TEXREG_MLC 5 /* GFX_OP_MAP_LOD_CTL */ +#define I810_TEXREG_MLL 6 /* GFX_OP_MAP_LOD_LIMITS */ +#define I810_TEXREG_MCS 7 /* GFX_OP_MAP_COORD_SETS ??? */ +#define I810_TEX_SETUP_SIZE 8 + +#define I810_FRONT 0x1 +#define I810_BACK 0x2 +#define I810_DEPTH 0x4 + + typedef struct _drm_i810_init { - enum { - I810_INIT_DMA = 0x01, - I810_CLEANUP_DMA = 0x02 + enum { + I810_INIT_DMA = 0x01, + I810_CLEANUP_DMA = 0x02 } func; - int ring_map_idx; - int buffer_map_idx; + int ring_map_idx; + int buffer_map_idx; int sarea_priv_offset; - unsigned long ring_start; - unsigned long ring_end; - unsigned long ring_size; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; } drm_i810_init_t; /* Warning: If you change the SAREA structure you must change the Xserver @@ -46,6 +123,11 @@ typedef struct _drm_i810_tex_region { } drm_i810_tex_region_t; typedef struct _drm_i810_sarea { + unsigned int ContextState[I810_CTX_SETUP_SIZE]; + unsigned int BufferState[I810_DEST_SETUP_SIZE]; + unsigned int TexState[2][I810_TEX_SETUP_SIZE]; + unsigned int dirty; + unsigned int nbox; drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS]; @@ -72,12 +154,18 @@ typedef struct _drm_i810_sarea { int last_dispatch; /* age of the most recently dispatched buffer */ int last_quiescent; /* */ int ctxOwner; /* last context to upload state */ + + int vertex_prim; + } drm_i810_sarea_t; -typedef struct _drm_i810_general { - int idx; - int used; -} drm_i810_general_t; +typedef struct _drm_i810_clear { + int clear_color; + int clear_depth; + int flags; +} drm_i810_clear_t; + + /* These may be placeholders if we have more cliprects than * I810_NR_SAREA_CLIPRECTS. In that case, the client sets discard to @@ -90,4 +178,11 @@ typedef struct _drm_i810_vertex { int discard; /* client is finished with the buffer? */ } drm_i810_vertex_t; +typedef struct drm_i810_dma { + void *virtual; + int request_idx; + int request_size; + int granted; +} drm_i810_dma_t; + #endif /* _I810_DRM_H_ */ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/r128_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/r128_drm.h new file mode 100644 index 000000000..0379a5fae --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/r128_drm.h @@ -0,0 +1,111 @@ +/* r128_drm.h -- Public header for the r128 driver + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + */ + +#ifndef _R128_DRM_H_ +#define _R128_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmR128.h) + */ +typedef struct drm_r128_init { + enum { + R128_INIT_CCE = 0x01, + R128_CLEANUP_CCE = 0x02 + } func; + int sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_fifo_size; + int cce_secure; + int ring_size; + int usec_timeout; + + int fb_offset; + int agp_ring_offset; + int agp_read_ptr_offset; + int agp_vertbufs_offset; + int agp_indbufs_offset; + int agp_textures_offset; + int mmio_offset; +} drm_r128_init_t; + +typedef struct drm_r128_packet { + unsigned long *buffer; + int count; + int flags; +} drm_r128_packet_t; + +typedef enum drm_r128_prim { + _DRM_R128_PRIM_NONE = 0x0001, + _DRM_R128_PRIM_POINT = 0x0002, + _DRM_R128_PRIM_LINE = 0x0004, + _DRM_R128_PRIM_POLY_LINE = 0x0008, + _DRM_R128_PRIM_TRI_LIST = 0x0010, + _DRM_R128_PRIM_TRI_FAN = 0x0020, + _DRM_R128_PRIM_TRI_STRIP = 0x0040, + _DRM_R128_PRIM_TRI_TYPE2 = 0x0080 +} drm_r128_prim_t; + +typedef struct drm_r128_vertex { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int send_count; /* Number of buffers to send */ + int *send_indices; /* List of handles to buffers */ + int *send_sizes; /* Lengths of data to send */ + drm_r128_prim_t prim; /* Primitive type */ + int request_count; /* Number of buffers requested */ + int *request_indices; /* Buffer information */ + int *request_sizes; + int granted_count; /* Number of buffers granted */ +} drm_r128_vertex_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (r128_sarea.h) + */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +typedef struct drm_tex_region { + unsigned char next, prev; + unsigned char in_use; + int age; +} drm_tex_region_t; + +typedef struct drm_r128_sarea { + drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + int tex_age[R128_NR_TEX_HEAPS]; + int ctx_owner; + int ring_write; +} drm_r128_sarea_t; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmI810.c b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmI810.c index 1248c70a9..067c6376e 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmI810.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmI810.c @@ -58,23 +58,29 @@ Bool drmI810CleanupDma(int driSubFD) return TRUE; } -Bool drmI810InitDma(int driSubFD, unsigned long start, unsigned long end, - unsigned long size, int ring_map_idx, int buffer_map_idx, - int sarea_off) +Bool drmI810InitDma(int driSubFD, drmI810Init *info) { drm_i810_init_t init; memset(&init, 0, sizeof(drm_i810_init_t)); + init.func = I810_INIT_DMA; - init.ring_map_idx = ring_map_idx; - init.buffer_map_idx = buffer_map_idx; - init.ring_start = start; - init.ring_end = end; - init.ring_size = size; - init.sarea_priv_offset = sarea_off; + init.ring_map_idx = info->ring_map_idx; + init.buffer_map_idx = info->buffer_map_idx; + init.ring_start = info->start; + init.ring_end = info->end; + init.ring_size = info->size; + init.sarea_priv_offset = info->sarea_off; + init.front_offset = info->front_offset; + init.back_offset = info->back_offset; + init.depth_offset = info->depth_offset; + init.w = info->w; + init.h = info->h; + init.pitch = info->pitch; + init.pitch_bits = info->pitch_bits; if(ioctl(driSubFD, DRM_IOCTL_I810_INIT, &init)) { - return FALSE; - } + return FALSE; + } return TRUE; } diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmR128.c b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmR128.c new file mode 100644 index 000000000..4195c90ba --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/xf86drmR128.c @@ -0,0 +1,198 @@ +/* xf86drmR128.c -- User-level interface to Rage 128 DRM device + * Created: Sun Apr 9 18:13:54 2000 by kevin@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#ifdef XFree86Server +# include "xf86.h" +# include "xf86_OSproc.h" +# include "xf86_ansic.h" +# include "xf86Priv.h" +# define _DRM_MALLOC xalloc +# define _DRM_FREE xfree +# ifndef XFree86LOADER +# include <sys/stat.h> +# include <sys/mman.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <string.h> +# include <ctype.h> +# include <fcntl.h> +# include <errno.h> +# include <signal.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <sys/mman.h> +# include <sys/time.h> +# ifdef DRM_USE_MALLOC +# define _DRM_MALLOC malloc +# define _DRM_FREE free +extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); +extern int xf86RemoveSIGIOHandler(int fd); +# else +# include <Xlibint.h> +# define _DRM_MALLOC Xmalloc +# define _DRM_FREE Xfree +# endif +#endif + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include "xf86drm.h" +#include "xf86drmR128.h" +#include "drm.h" + +int drmR128InitCCE(int fd, drmR128Init *info) +{ + drm_r128_init_t init; + + memset(&init, 0, sizeof(drm_r128_init_t)); + + init.func = R128_INIT_CCE; + init.sarea_priv_offset = info->sarea_priv_offset; + init.is_pci = info->is_pci; + init.cce_mode = info->cce_mode; + init.cce_fifo_size = info->cce_fifo_size; + init.cce_secure = info->cce_secure; + init.ring_size = info->ring_size; + init.usec_timeout = info->usec_timeout; + + init.fb_offset = info->fb_offset; + init.agp_ring_offset = info->agp_ring_offset; + init.agp_read_ptr_offset = info->agp_read_ptr_offset; + init.agp_vertbufs_offset = info->agp_vertbufs_offset; + init.agp_indbufs_offset = info->agp_indbufs_offset; + init.agp_textures_offset = info->agp_textures_offset; + init.mmio_offset = info->mmio_offset; + + if (ioctl(fd, DRM_IOCTL_R128_INIT, &init)) return -errno; + + return 0; +} + +int drmR128CleanupCCE(int fd) +{ + drm_r128_init_t init; + + memset(&init, 0, sizeof(drm_r128_init_t)); + + init.func = R128_CLEANUP_CCE; + + if (ioctl(fd, DRM_IOCTL_R128_INIT, &init)) return -errno; + + return 0; +} + +int drmR128EngineReset(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_RESET, NULL)) return -errno; + + return 0; +} + +int drmR128EngineFlush(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_FLUSH, NULL)) return -errno; + + return 0; +} + +int drmR128CCEWaitForIdle(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_CCEIDL, NULL)) return -errno; + + return 0; +} + +int drmR128SubmitPackets(int fd, CARD32 *buffer, int *count, int flags) +{ + drm_r128_packet_t packet; + int ret; + + memset(&packet, 0, sizeof(drm_r128_packet_t)); + + packet.count = *count; + packet.flags = flags; + + while (packet.count > 0) { + packet.buffer = buffer + (*count - packet.count); + ret = ioctl(fd, DRM_IOCTL_R128_PACKET, &packet); + if (ret < 0 && ret != -EAGAIN) { + *count = packet.count; + return -errno; + } + } + + *count = 0; + return 0; +} + +int drmR128GetVertexBuffers(int fd, int count, int *indices, int *sizes) +{ + drm_r128_vertex_t v; + + v.send_count = 0; + v.send_indices = NULL; + v.send_sizes = NULL; + v.prim = DRM_R128_PRIM_NONE; + v.request_count = count; + v.request_indices = indices; + v.request_sizes = sizes; + v.granted_count = 0; + + if (ioctl(fd, DRM_IOCTL_R128_VERTEX, &v)) return -errno; + + return v.granted_count; +} + +int drmR128FlushVertexBuffers(int fd, int count, int *indices, + int *sizes, drmR128PrimType prim) +{ + drm_r128_vertex_t v; + + v.send_count = count; + v.send_indices = indices; + v.send_sizes = sizes; + v.prim = prim; + v.request_count = 0; + v.request_indices = NULL; + v.request_sizes = NULL; + v.granted_count = 0; + + if (ioctl(fd, DRM_IOCTL_R128_VERTEX, &v) < 0) return -errno; + + return 0; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/Imakefile b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/Imakefile index 96388450b..fdaecb972 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/Imakefile +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/Imakefile @@ -13,15 +13,16 @@ MOBJ = drmmodule.o MTRR_DEFINES = -DHAS_MTRR_SUPPORT #endif -SRCS = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c $(MSRC) -OBJS = xf86drm.o xf86drmHash.o xf86drmRandom.o xf86drmSL.o $(MOBJ) - +SRCS = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmI810.c xf86drmMga.c xf86drmR128.c $(MSRC) +OBJS = xf86drm.o xf86drmHash.o xf86drmRandom.o xf86drmSL.o xf86drmI810.o xf86drmMga.o xf86drmR128.o $(MOBJ) INCLUDES = -I$(XF86COMSRC) -I$(XF86OSSRC) -I. -I$(SERVERSRC)/include \ -I$(XINCLUDESRC) -I$(EXTINCSRC) -I../.. -Ikernel DEFINES = $(MTRR_DEFINES) $(GLX_DEFINES) +#if DoLoadableServer + ModuleObjectRule() LibraryModuleTarget(drm,$(OBJS)) NormalLintTarget($(SRCS)) @@ -30,6 +31,14 @@ NormalLintTarget($(SRCS)) InstallLibraryModule(drm,$(MODULEDIR),linux) #endif +#else + +SubdirLibraryRule($(OBJS)) +NormalLibraryObjectRule() + +#endif + + #define IHaveSubdirs SUBDIRS = kernel diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel index 44d75c487..a169473af 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel @@ -14,7 +14,8 @@ L_TARGET := libdrm.a L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \ + agpsupport.o M_OBJS := @@ -26,6 +27,14 @@ ifdef CONFIG_DRM_TDFX M_OBJS += tdfx.o endif +ifdef CONFIG_DRM_MGA +M_OBJS += mga.o +endif + +ifdef CONFIG_DRM_R128 +M_OBJS += r128.o +endif + include $(TOPDIR)/Rules.make gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) @@ -33,3 +42,12 @@ gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET) $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm + +i810.o: i810_drv.o i810_context.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ i810_drv.o i810_bufs.o i810_dma.o i810_context.o -L. -ldrm + +mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm + +r128.o: r128_drv.o r128_context.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ r128_drv.o r128_context.o -L. -ldrm diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux index 8a41f880b..368c3c850 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux @@ -1,8 +1,7 @@ # Makefile -- For the Direct Rendering Manager module (drm) # Created: Mon Jan 4 09:26:53 1999 by faith@precisioninsight.com -# Revised: Sun Feb 13 23:15:59 2000 by kevin@precisioninsight.com # -# Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. +# Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. # All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a @@ -31,12 +30,14 @@ # *** Setup -MODS= gamma.o tdfx.o +# **** End of SMP/MODVERSIONS detection + +MODS= gamma.o tdfx.o r128.o LIBS= libdrm.a PROGS= drmstat DRMOBJS= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o DRMHEADERS= drm.h drmP.h GAMMAOBJS= gamma_drv.o gamma_dma.o @@ -45,9 +46,14 @@ GAMMAHEADERS= gamma_drv.h $(DRMHEADERS) TDFXOBJS= tdfx_drv.o tdfx_context.o TDFXHEADERS= tdfx_drv.h $(DRMHEADERS) +R128OBJS= r128_drv.o r128_dma.o r128_bufs.o r128_context.o +R128HEADERS= r128_drv.h r128_drm.h $(DRMHEADERS) + PROGOBJS= drmstat.po xf86drm.po xf86drmHash.po xf86drmRandom.po sigio.po PROGHEADERS= xf86drm.h $(DRMHEADERS) +INC= /usr/include + CFLAGS= -O2 $(WARNINGS) WARNINGS= -Wall -Wwrite-strings -Wpointer-arith -Wcast-align \ -Wstrict-prototypes -Wshadow -Wnested-externs \ @@ -102,7 +108,27 @@ SMP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ | grep -s 'SMP = ' | cut -d' ' -f3) MODVERSIONS := $(shell gcc -E -I $(TREE) picker.c 2>/dev/null \ | grep -s 'MODVERSIONS = ' | cut -d' ' -f3) -all::;@echo KERNEL HEADERS IN $(TREE): SMP=${SMP} MODVERSIONS=${MODVERSIONS} +AGP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ + | grep -s 'AGP = ' | cut -d' ' -f3) +ifeq ($(AGP),0) +AGP := $(shell gcc -E -nostdinc -I$(TREE) picker.c 2>/dev/null \ + | grep -s 'AGP_MODULE = ' | cut -d' ' -f3) +endif + +ifeq ($(AGP),1) +MODCFLAGS += -DDRM_AGP +DRMOBJS += agpsupport.o +MODS += mga.o i810.o + +MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_context.o +MGAHEADERS= mga_drv.h $(DRMHEADERS) + +I810OBJS= i810_drv.o i810_dma.o i810_bufs.o i810_context.o +I810HEADERS= i810_drv.h $(DRMHEADERS) +endif + +all::;@echo KERNEL HEADERS IN $(TREE): SMP=${SMP} MODVERSIONS=${MODVERSIONS} \ + AGP=${AGP} all:: $(LIBS) $(MODS) $(PROGS) endif @@ -116,6 +142,7 @@ ifeq ($(MODVERSIONS),1) MODCFLAGS += -DMODVERSIONS -include $(TREE)/linux/modversions.h endif + # **** End of configuration libdrm.a: $(DRMOBJS) @@ -128,6 +155,17 @@ gamma.o: $(GAMMAOBJS) $(LIBS) tdfx.o: $(TDFXOBJS) $(LIBS) $(LD) -r $^ -o $@ +r128.o: $(R128OBJS) $(LIBS) + $(LD) -r $^ -o $@ + +ifeq ($(AGP),1) +mga.o: $(MGAOBJS) $(LIBS) + $(LD) -r $^ -o $@ + +i810.o: $(I810OBJS) $(LIBS) + $(LD) -r $^ -o $@ +endif + drmstat: $(PROGOBJS) $(CC) $(PRGCFLAGS) $^ $(PRGLIBS) -o $@ @@ -149,8 +187,12 @@ ChangeLog: $(DRMOBJS): $(DRMHEADERS) $(GAMMAOBJS): $(GAMMAHEADERS) $(TDFXOBJS): $(TDFXHEADERS) +$(R128OBJS): $(R128HEADERS) +ifeq ($(AGP),1) +$(MGAOBJS): $(MGAHEADERS) +$(I810OBJS): $(I810HEADERS) +endif $(PROGOBJS): $(PROGHEADERS) clean: - rm -f *.o *.po *~ core $(PROGS) - + rm -f *.o *.a *.po *~ core $(PROGS) diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/agpsupport.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/agpsupport.c index fb58154d6..14fb8b53f 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/agpsupport.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/agpsupport.c @@ -159,6 +159,8 @@ int drm_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, -EFAULT); if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) return -ENOMEM; + + memset(entry, 0, sizeof(*entry)); pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u32) request.type; @@ -237,6 +239,8 @@ int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd, page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; if ((retcode = drm_bind_agp(entry->memory, page))) return retcode; entry->bound = dev->agp->base + (page << PAGE_SHIFT); + DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", + dev->agp->base, entry->bound); return 0; } @@ -254,8 +258,10 @@ int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, if (!(entry = drm_agp_lookup_entry(dev, request.handle))) return -EINVAL; if (entry->bound) drm_unbind_agp(entry->memory); - entry->prev->next = entry->next; - entry->next->prev = entry->prev; + + if (entry->prev) entry->prev->next = entry->next; + else dev->agp->memory = entry->next; + if (entry->next) entry->next->prev = entry->prev; drm_free_agp(entry->memory, entry->pages); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return 0; @@ -269,15 +275,12 @@ drm_agp_head_t *drm_agp_init(void) for (fill = &drm_agp_fill[0]; fill->name; fill++) { char *n = (char *)fill->name; -#if 0 - *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n); -#endif *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n); - printk("%s resolves to 0x%08lx\n", n, (*fill->f).address); + DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address); if (!(*fill->f).address) agp_available = 0; } - printk("agp_available = %d\n", agp_available); + DRM_DEBUG("agp_available = %d\n", agp_available); if (agp_available) { if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h index 3af5d5b1e..c63d0f637 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h @@ -1,8 +1,7 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Mon Feb 14 00:15:23 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -71,9 +70,10 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; -/* Seperate include files for the i810/mga specific structures */ +/* Seperate include files for the i810/mga/r128 specific structures */ #include "mga_drm.h" #include "i810_drm.h" +#include "r128_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -341,12 +341,23 @@ typedef struct drm_agp_info { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) #define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) /* I810 specific ioctls */ #define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) #define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) #define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) #define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOW( 0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) + +/* Rage 128 specific ioctls */ +#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) +#define DRM_IOCTL_R128_RESET DRM_IO( 0x41) +#define DRM_IOCTL_R128_FLUSH DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x43) +#define DRM_IOCTL_R128_PACKET DRM_IOW( 0x44, drm_r128_packet_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x45, drm_r128_vertex_t) #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h index 312fba36f..43670e28a 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h @@ -1,8 +1,7 @@ /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Sun Feb 13 23:34:30 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -48,8 +47,12 @@ #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif +#ifdef DRM_AGP +#include <linux/types.h> +#include <linux/agp_backend.h> +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include <asm/spinlock.h> +#include <linux/tqueue.h> #include <linux/poll.h> #endif #include "drm.h" @@ -69,21 +72,27 @@ #define DRM_FLAG_DEBUG 0x01 #define DRM_FLAG_NOCTX 0x02 -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /* Backward compatibility section */ /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ @@ -218,8 +227,8 @@ typedef struct drm_magic_entry { } drm_magic_entry_t; typedef struct drm_magic_head { - struct drm_magic_entry *head; - struct drm_magic_entry *tail; + struct drm_magic_entry *head; + struct drm_magic_entry *tail; } drm_magic_head_t; typedef struct drm_vma_entry { @@ -235,6 +244,7 @@ typedef struct drm_buf { int used; /* Amount of buffer in use (for DMA) */ unsigned long offset; /* Byte offset (used internally) */ void *address; /* Address of buffer */ + unsigned long bus_address; /* Bus address of buffer */ struct drm_buf *next; /* Kernel-only: used for free list */ __volatile__ int waiting; /* On kernel DMA queue */ __volatile__ int pending; /* On hardware DMA queue */ @@ -250,12 +260,16 @@ typedef struct drm_buf { DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 } list; /* Which list we're on */ + #if DRM_DMA_HISTOGRAM cycles_t time_queued; /* Queued to kernel DMA queue */ cycles_t time_dispatched; /* Dispatched to hardware */ cycles_t time_completed; /* Completed by hardware */ cycles_t time_freed; /* Back on freelist */ #endif + + int dev_priv_size; /* Size of buffer private stoarge */ + void *dev_private; /* Per-buffer private storage */ } drm_buf_t; #if DRM_DMA_HISTOGRAM @@ -376,6 +390,9 @@ typedef struct drm_device_dma { int page_count; unsigned long *pagelist; unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01 + } flags; /* DMA support */ drm_buf_t *this_buffer; /* Buffer being sent */ @@ -384,6 +401,41 @@ typedef struct drm_device_dma { wait_queue_head_t waiting; /* Processes waiting on free bufs */ } drm_device_dma_t; +#ifdef DRM_AGP +typedef struct drm_agp_mem { + unsigned long handle; + agp_memory *memory; + unsigned long bound; /* address */ + int pages; + struct drm_agp_mem *prev; + struct drm_agp_mem *next; +} drm_agp_mem_t; + +typedef struct drm_agp_head { + agp_kern_info agp_info; + const char *chipset; + drm_agp_mem_t *memory; + unsigned long mode; + int enabled; + int acquired; + unsigned long base; + int agp_mtrr; +} drm_agp_head_t; + +typedef struct { + void (*free_memory)(agp_memory *); + agp_memory *(*allocate_memory)(size_t, u32); + int (*bind_memory)(agp_memory *, off_t); + int (*unbind_memory)(agp_memory *); + void (*enable)(u32); + int (*acquire)(void); + void (*release)(void); + void (*copy_info)(agp_kern_info *); +} drm_agp_func_t; + +extern drm_agp_func_t drm_agp; +#endif + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -462,6 +514,12 @@ typedef struct drm_device { struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ wait_queue_head_t buf_readers; /* Processes waiting to read */ wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ + +#ifdef DRM_AGP + drm_agp_head_t *agp; +#endif + unsigned long *ctx_bitmap; + void *dev_private; } drm_device_t; @@ -533,6 +591,14 @@ extern void drm_free_pages(unsigned long address, int order, extern void *drm_ioremap(unsigned long offset, unsigned long size); extern void drm_ioremapfree(void *pt, unsigned long size); +#ifdef DRM_AGP +extern agp_memory *drm_alloc_agp(int pages, u32 type); +extern int drm_free_agp(agp_memory *handle, int pages); +extern int drm_bind_agp(agp_memory *handle, unsigned int start); +extern int drm_unbind_agp(agp_memory *handle); +#endif + + /* Buffer management support (bufs.c) */ extern int drm_order(unsigned long size); extern int drm_addmap(struct inode *inode, struct file *filp, @@ -642,5 +708,32 @@ extern int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags); extern int drm_flush_block_and_flush(drm_device_t *dev, int context, drm_lock_flags_t flags); + + /* Context Bitmap support (ctxbitmap.c) */ +extern int drm_ctxbitmap_init(drm_device_t *dev); +extern void drm_ctxbitmap_cleanup(drm_device_t *dev); +extern int drm_ctxbitmap_next(drm_device_t *dev); +extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + +#ifdef DRM_AGP + /* AGP/GART support (agpsupport.c) */ +extern drm_agp_head_t *drm_agp_init(void); +extern int drm_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#endif #endif #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_bufs.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_bufs.c index 49455b434..9737ae92d 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_bufs.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_bufs.c @@ -32,152 +32,28 @@ #define __NO_VERSION__ #include "drmP.h" +#include "i810_drv.h" #include "linux/un.h" int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - drm_buf_desc_t request; - drm_buf_entry_t *entry; - drm_buf_t *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i; - - if (!dma) return -EINVAL; - - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); - - count = request.count; - order = drm_order(request.size); - size = 1 << order; - agp_offset = request.agp_start; - alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - byte_count = 0; - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - if (dev->queue_count) return -EBUSY; /* Not while in use */ - spin_lock(&dev->count_lock); - if (dev->buf_use) { - spin_unlock(&dev->count_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->count_lock); - - down(&dev->struct_sem); - entry = &dma->bufs[order]; - if (entry->buf_count) { - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); - if (!entry->buflist) { - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - - entry->buf_size = size; - entry->page_order = page_order; - - while(entry->buf_count < count) { - for(offset = 0; offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = agp_offset - dev->agp->base + offset;/* ?? */ - buf->bus_address = agp_offset + offset; - buf->address = agp_offset + offset + dev->agp->base; - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - init_waitqueue_head(&buf->dma_wait); - buf->pid = 0; -#if DRM_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -#endif - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } - byte_count += PAGE_SIZE << page_order; - } - - dma->buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), - DRM_MEM_BUFS); - for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) - dma->buflist[i] = &entry->buflist[i - dma->buf_count]; - - dma->buf_count += entry->buf_count; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - - drm_freelist_create(&entry->freelist, entry->buf_count); - for (i = 0; i < entry->buf_count; i++) { - drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); - } - - up(&dev->struct_sem); - - request.count = entry->buf_count; - request.size = size; - - copy_to_user_ret((drm_buf_desc_t *)arg, - &request, - sizeof(request), - -EFAULT); - - atomic_dec(&dev->buf_alloc); - return 0; -} - -int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - drm_buf_desc_t request; - int count; - int order; - int size; - int total; - int page_order; - drm_buf_entry_t *entry; - unsigned long page; - drm_buf_t *buf; - int alignment; - unsigned long offset; - int i; - int byte_count; - int page_count; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; if (!dma) return -EINVAL; @@ -186,20 +62,17 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, sizeof(request), -EFAULT); - count = request.count; - order = drm_order(request.size); - size = 1 << order; - - DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n", - request.count, request.size, size, order, dev->queue_count); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; - if (dev->queue_count) return -EBUSY; /* Not while in use */ - + count = request.count; + order = drm_order(request.size); + size = 1 << order; + agp_offset = request.agp_start; alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - + total = PAGE_SIZE << page_order; + byte_count = 0; + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ spin_lock(&dev->count_lock); if (dev->buf_use) { spin_unlock(&dev->count_lock); @@ -207,15 +80,15 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, } atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - + down(&dev->struct_sem); entry = &dma->bufs[order]; if (entry->buf_count) { up(&dev->struct_sem); atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ + return -ENOMEM; /* May only call once for each order */ } - + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { @@ -224,69 +97,45 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, return -ENOMEM; } memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - - entry->seglist = drm_alloc(count * sizeof(*entry->seglist), - DRM_MEM_SEGS); - if (!entry->seglist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), - DRM_MEM_BUFS); - up(&dev->struct_sem); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memset(entry->seglist, 0, count * sizeof(*entry->seglist)); - - dma->pagelist = drm_realloc(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - DRM_DEBUG("pagelist: %d entries\n", - dma->page_count + (count << page_order)); - - - entry->buf_size = size; + + entry->buf_size = size; entry->page_order = page_order; - byte_count = 0; - page_count = 0; - while (entry->buf_count < count) { - if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break; - entry->seglist[entry->seg_count++] = page; - for (i = 0; i < (1 << page_order); i++) { - DRM_DEBUG("page %d @ 0x%08lx\n", - dma->page_count + page_count, - page + PAGE_SIZE * i); - dma->pagelist[dma->page_count + page_count++] - = page + PAGE_SIZE * i; - } - for (offset = 0; - offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = (dma->byte_count + byte_count + offset); - buf->address = (void *)(page + offset); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - init_waitqueue_head(&buf->dma_wait); - buf->pid = 0; + offset = 0; + + while(entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = offset; + buf->bus_address = dev->agp->base + agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->agp->base); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), + DRM_MEM_BUFS); + buf->dev_priv_size = sizeof(drm_i810_buf_priv_t); + memset(buf->dev_private, 0, sizeof(drm_i810_buf_priv_t)); + #if DRM_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; #endif - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } + offset = offset + alignment; + entry->buf_count++; byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); } - + dma->buflist = drm_realloc(dma->buflist, dma->buf_count * sizeof(*dma->buflist), (dma->buf_count + entry->buf_count) @@ -294,45 +143,43 @@ int i810_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd, DRM_MEM_BUFS); for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) dma->buflist[i] = &entry->buflist[i - dma->buf_count]; - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += entry->seg_count << page_order; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; drm_freelist_create(&entry->freelist, entry->buf_count); for (i = 0; i < entry->buf_count; i++) { drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); } - + up(&dev->struct_sem); - + request.count = entry->buf_count; request.size = size; - + copy_to_user_ret((drm_buf_desc_t *)arg, &request, sizeof(request), -EFAULT); - + atomic_dec(&dev->buf_alloc); + dma->flags = _DRM_DMA_USE_AGP; return 0; } int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_buf_desc_t request; + drm_buf_desc_t request; - copy_from_user_ret(&request, - (drm_buf_desc_t *)arg, - sizeof(request), - -EFAULT); + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); - if(request.flags & _DRM_AGP_BUFFER) - return i810_addbufs_agp(inode, filp, cmd, arg); - else - return i810_addbufs_pci(inode, filp, cmd, arg); + if(request.flags & _DRM_AGP_BUFFER) + return i810_addbufs_agp(inode, filp, cmd, arg); + else + return -EINVAL; } int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd, @@ -486,99 +333,3 @@ int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int i810_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - const int zero = 0; - unsigned long virtual; - unsigned long address; - drm_buf_map_t request; - int i; - - if (!dma) return -EINVAL; - - DRM_DEBUG("\n"); - - spin_lock(&dev->count_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); - return -EBUSY; - } - ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); - - copy_from_user_ret(&request, - (drm_buf_map_t *)arg, - sizeof(request), - -EFAULT); - - if (request.count >= dma->buf_count) { - if(dma->flags & _DRM_DMA_USE_AGP) { - /* This is an ugly vicious hack */ - drm_map_t *map = NULL; - for(i = 0; i < dev->map_count; i++) { - map = dev->maplist[i]; - if(map->type == _DRM_AGP) break; - } - if (i >= dev->map_count || !map) { - retcode = -EINVAL; - goto done; - } - - virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, - MAP_SHARED, (unsigned long)map->handle); - } - else { - virtual = do_mmap(filp, 0, dma->byte_count, - PROT_READ|PROT_WRITE, MAP_SHARED, 0); - } - if (virtual > -1024UL) { - /* Real error */ - retcode = (signed long)virtual; - goto done; - } - request.virtual = (void *)virtual; - - for (i = 0; i < dma->buf_count; i++) { - if (copy_to_user(&request.list[i].idx, - &dma->buflist[i]->idx, - sizeof(request.list[0].idx))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].total, - &dma->buflist[i]->total, - sizeof(request.list[0].total))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].used, - &zero, - sizeof(zero))) { - retcode = -EFAULT; - goto done; - } - address = virtual + dma->buflist[i]->offset; - if (copy_to_user(&request.list[i].address, - &address, - sizeof(address))) { - retcode = -EFAULT; - goto done; - } - } - } -done: - request.count = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - - copy_to_user_ret((drm_buf_map_t *)arg, - &request, - sizeof(request), - -EFAULT); - - return retcode; -} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c index 09959b657..f041f2098 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c @@ -25,8 +25,9 @@ * * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com> * Jeff Hartmann <jhartmann@precisioninsight.com> + * Keith Whitwell <keithw@precisioninsight.com> * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c,v 1.1 2000/02/11 17:26:04 dawes Exp $ + * $XFree86$ * */ @@ -36,6 +37,13 @@ #include <linux/interrupt.h> /* For task queue support */ +#define I810_BUF_FREE 2 +#define I810_BUF_CLIENT 1 +#define I810_BUF_HARDWARE 0 + +#define I810_BUF_UNMAPPED 0 +#define I810_BUF_MAPPED 1 + #define I810_REG(reg) 2 #define I810_BASE(reg) ((unsigned long) \ dev->maplist[I810_REG(reg)]->handle) @@ -43,544 +51,835 @@ #define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) #define I810_READ(reg) I810_DEREF(reg) #define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) - -void i810_dma_init(drm_device_t *dev) +#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) +#define I810_READ16(reg) I810_DEREF16(reg) +#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) + +#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0); + +static inline void i810_print_status_page(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_init\n"); + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; + u32 *temp = (u32 *)dev_priv->hw_status_page; + int i; + + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 6; i < dma->buf_count + 6; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); + } } -void i810_dma_cleanup(drm_device_t *dev) +static drm_buf_t *i810_freelist_get(drm_device_t *dev) { - printk(KERN_INFO "i810_dma_cleanup\n"); + drm_device_dma_t *dma = dev->dma; + int i; + int used; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, + I810_BUF_CLIENT); + if(used == I810_BUF_FREE) { + return buf; + } + } + return NULL; } -static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address, - unsigned long length) +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - printk(KERN_INFO "i810_dma_dispatch\n"); + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int used; + + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); + if(used != I810_BUF_CLIENT) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + + return 0; } -static inline void i810_dma_quiescent(drm_device_t *dev) +static struct file_operations i810_buffer_fops = { + open: i810_open, + flush: drm_flush, + release: i810_release, + ioctl: i810_ioctl, + mmap: i810_mmap_buffers, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_buf_t *buf = dev_priv->mmap_buffer; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + vma->vm_flags |= (VM_IO | VM_DONTCOPY); + vma->vm_file = filp; + + buf_priv->currently_mapped = I810_BUF_MAPPED; + + if (remap_page_range(vma->vm_start, + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) return -EAGAIN; + return 0; } -static inline void i810_dma_ready(drm_device_t *dev) +static int i810_map_buffer(drm_buf_t *buf, struct file *filp) { - i810_dma_quiescent(dev); - printk(KERN_INFO "i810_dma_ready\n"); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; + struct file_operations *old_fops; + int retcode = 0; + + if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL; + down(¤t->mm->mmap_sem); + old_fops = filp->f_op; + filp->f_op = &i810_buffer_fops; + dev_priv->mmap_buffer = buf; + buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, + PROT_READ|PROT_WRITE, + MAP_SHARED, + buf->bus_address); + dev_priv->mmap_buffer = NULL; + filp->f_op = old_fops; + if ((unsigned long)buf_priv->virtual > -1024UL) { + /* Real error */ + DRM_DEBUG("mmap error\n"); + retcode = (signed int)buf_priv->virtual; + buf_priv->virtual = 0; + } + up(¤t->mm->mmap_sem); + return retcode; } -static inline int i810_dma_is_ready(drm_device_t *dev) +static int i810_unmap_buffer(drm_buf_t *buf) { + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int retcode = 0; - i810_dma_quiescent(dev); + if(buf_priv->currently_mapped != I810_BUF_MAPPED) return -EINVAL; + down(¤t->mm->mmap_sem); + retcode = do_munmap((unsigned long)buf_priv->virtual, + (size_t) buf->total); + buf_priv->currently_mapped = I810_BUF_UNMAPPED; + buf_priv->virtual = 0; + up(¤t->mm->mmap_sem); - printk(KERN_INFO "i810_dma_is_ready\n"); - return 1; + return retcode; } - -static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, + struct file *filp) { - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; - - atomic_inc(&dev->total_irq); - if (i810_dma_is_ready(dev)) { - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; - } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; - } - clear_bit(0, &dev->dma_flag); - - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + drm_file_t *priv = filp->private_data; + drm_buf_t *buf; + drm_i810_buf_priv_t *buf_priv; + int retcode = 0; + + buf = i810_freelist_get(dev); + if (!buf) { + retcode = -ENOMEM; + DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode); + goto out_get_buf; + } + + retcode = i810_map_buffer(buf, filp); + if(retcode) { + i810_freelist_put(dev, buf); + DRM_DEBUG("mapbuf failed in %s retcode %d\n", + __FUNCTION__, retcode); + goto out_get_buf; } + buf->pid = priv->pid; + buf_priv = buf->dev_private; + d->granted = 1; + d->request_idx = buf->idx; + d->request_size = buf->total; + d->virtual = buf_priv->virtual; + +out_get_buf: + return retcode; } -/* Only called by i810_dma_schedule. */ -static int i810_do_dma(drm_device_t *dev, int locked) +static unsigned long i810_alloc_page(drm_device_t *dev) { - unsigned long address; - unsigned long length; - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t dma_start, dma_stop; -#endif - - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_dma); - return -EBUSY; - } + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) + return 0; -#if DRM_DMA_HISTOGRAM - dma_start = get_cycles(); -#endif - - if (!dma->next_buffer) { - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } + atomic_inc(&mem_map[MAP_NR((void *) address)].count); + set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); + + return address; +} - buf = dma->next_buffer; - address = (unsigned long)buf->bus_address; - length = buf->used; +static void i810_free_page(drm_device_t *dev, unsigned long page) +{ + if(page == 0UL) + return; + atomic_dec(&mem_map[MAP_NR((void *) page)].count); + clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); + wake_up(&mem_map[MAP_NR((void *) page)].wait); + free_page(page); + return; +} - DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", - buf->context, buf->idx, length); - - if (buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - if (!length) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (!i810_dma_is_ready(dev)) { - clear_bit(0, &dev->dma_flag); - return -EBUSY; - } +static int i810_dma_cleanup(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; - if (buf->while_locked) { - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { - DRM_ERROR("Dispatching buffer %d from pid %d" - " \"while locked\", but no lock held\n", - buf->idx, buf->pid); + if(dev->dev_private) { + int i; + drm_i810_private_t *dev_priv = + (drm_i810_private_t *) dev->dev_private; + + if(dev_priv->ring.virtual_start) { + drm_ioremapfree((void *) dev_priv->ring.virtual_start, + dev_priv->ring.Size); + } + if(dev_priv->hw_status_page != 0UL) { + i810_free_page(dev, dev_priv->hw_status_page); + /* Need to rewrite hardware status page */ + I810_WRITE(0x02080, 0x1ffff000); } - } else { - if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - return -EBUSY; + drm_free(dev->dev_private, sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_ioremapfree(buf_priv->kernel_virtual, buf->total); } } + return 0; +} - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - /* PRE: dev->last_context != buf->context */ - if (drm_context_switch(dev, dev->last_context, buf->context)) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); +static int i810_wait_ring(drm_device_t *dev, int n) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; + unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + + end = jiffies + (HZ*3); + while (ring->space < n) { + int i; + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; + + if (ring->head != last_head) + end = jiffies + (HZ*3); + + iters++; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; } - retcode = -EBUSY; - goto cleanup; - - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - } - - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; -#if DRM_DMA_HISTOGRAM - buf->time_dispatched = get_cycles(); -#endif - - i810_dma_dispatch(dev, address, length); - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = buf; - - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - if (!buf->while_locked && !dev->context_flag && !locked) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + for (i = 0 ; i < 2000 ; i++) ; } -cleanup: - - clear_bit(0, &dev->dma_flag); - -#if DRM_DMA_HISTOGRAM - dma_stop = get_cycles(); - atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); -#endif - return retcode; +out_wait_ring: + return iters; } -static void i810_dma_schedule_timer_wrapper(unsigned long dev) +static void i810_kernel_lost_context(drm_device_t *dev) { - i810_dma_schedule((drm_device_t *)dev, 0); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I810_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; } -static void i810_dma_schedule_tq_wrapper(void *dev) +static int i810_freelist_init(drm_device_t *dev) { - i810_dma_schedule(dev, 0); + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + int my_idx = 24; + u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); + int i; + + if(dma->buf_count > 1019) { + /* Not enough space in the status page for the freelist */ + return -EINVAL; + } + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->in_use = hw_status++; + buf_priv->my_use_idx = my_idx; + my_idx += 4; + + *buf_priv->in_use = I810_BUF_FREE; + + buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, + buf->total); + } + return 0; } -int i810_dma_schedule(drm_device_t *dev, int locked) +static int i810_dma_initialize(drm_device_t *dev, + drm_i810_private_t *dev_priv, + drm_i810_init_t *init) { - int next; - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t schedule_start; -#endif + drm_map_t *sarea_map; - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; + dev->dev_private = (void *) dev_priv; + memset(dev_priv, 0, sizeof(drm_i810_private_t)); + + if (init->ring_map_idx >= dev->map_count || + init->buffer_map_idx >= dev->map_count) { + i810_dma_cleanup(dev); + DRM_ERROR("ring_map or buffer_map are invalid\n"); + return -EINVAL; + } + + dev_priv->ring_map_idx = init->ring_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_i810_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + + atomic_set(&dev_priv->flush_done, 0); + init_waitqueue_head(&dev_priv->flush_queue); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + + dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + + init->ring_start, + init->ring_size); + + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + if (dev_priv->ring.virtual_start == NULL) { + i810_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; } - missed = atomic_read(&dma->total_missed_sched); -#if DRM_DMA_HISTOGRAM - schedule_start = get_cycles(); -#endif + dev_priv->w = init->w; + dev_priv->h = init->h; + dev_priv->pitch = init->pitch; + dev_priv->back_offset = init->back_offset; + dev_priv->depth_offset = init->depth_offset; -again: - if (dev->context_flag) { - clear_bit(0, &dev->interrupt_flag); - return -EBUSY; + dev_priv->front_di1 = init->front_offset | init->pitch_bits; + dev_priv->back_di1 = init->back_offset | init->pitch_bits; + dev_priv->zi1 = init->depth_offset | init->pitch_bits; + + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = i810_alloc_page(dev); + memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); + if(dev_priv->hw_status_page == 0UL) { + i810_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; } - if (dma->next_buffer) { - /* Unsent buffer that was previously - selected, but that couldn't be sent - because the lock could not be obtained - or the DMA engine wasn't ready. Try - again. */ - atomic_inc(&dma->total_tried); - if (!(retcode = i810_do_dma(dev, locked))) { - atomic_inc(&dma->total_hit); - ++processed; - } - } else { - do { - next = drm_select_queue(dev, - i810_dma_schedule_timer_wrapper); - if (next >= 0) { - q = dev->queuelist[next]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - } - } - } while (next >= 0 && !dma->next_buffer); - if (dma->next_buffer) { - if (!(retcode = i810_do_dma(dev, locked))) { - ++processed; - } - } + DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + + I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); + DRM_DEBUG("Enabled hardware status page\n"); + + /* Now we need to init our freelist */ + if(i810_freelist_init(dev) != 0) { + i810_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" + " the freelist\n"); + return -ENOMEM; } + return 0; +} - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (i810_dma_is_ready(dev)) goto again; - } - if (processed && i810_dma_is_ready(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } - } +int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv; + drm_i810_init_t init; + int retcode = 0; - clear_bit(0, &dev->interrupt_flag); + copy_from_user_ret(&init, (drm_i810_init_t *)arg, + sizeof(init), -EFAULT); -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() - - schedule_start)]); -#endif - return retcode; + switch(init.func) { + case I810_INIT_DMA: + dev_priv = drm_alloc(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + retcode = i810_dma_cleanup(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; } -static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d) -{ - unsigned long address; - unsigned long length; - int must_free = 0; - int retcode = 0; - int i; - int idx; - drm_buf_t *buf; - drm_buf_t *last_buf = NULL; - drm_device_dma_t *dma = dev->dma; - DECLARE_WAITQUEUE(entry, current); - /* Turn off interrupt handling */ - while (test_and_set_bit(0, &dev->interrupt_flag)) { - schedule(); - if (signal_pending(current)) return -EINTR; - } - if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { - while (!drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - schedule(); - if (signal_pending(current)) { - clear_bit(0, &dev->interrupt_flag); - return -EINTR; - } - } - ++must_free; + +/* Most efficient way to verify state for the i810 is as it is + * emitted. Non-conformant state is silently dropped. + * + * Use 'volatile' & local var tmp to force the emitted values to be + * identical to the verified ones. + */ +static void i810EmitContextVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_CTX_SETUP_SIZE ); + + OUT_RING( GFX_OP_COLOR_FACTOR ); + OUT_RING( code[I810_CTXREG_CF1] ); + + OUT_RING( GFX_OP_STIPPLE ); + OUT_RING( code[I810_CTXREG_ST1] ); + + for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) + { + OUT_RING( tmp ); + j++; + } } - atomic_inc(&dma->total_prio); - for (i = 0; i < d->send_count; i++) { - idx = d->send_indices[i]; - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - d->send_indices[i], dma->buf_count - 1); - continue; - } - buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - retcode = -EINVAL; - goto cleanup; - } - if (buf->list != DRM_LIST_NONE) { - DRM_ERROR("Process %d using %d's buffer on list %d\n", - current->pid, buf->pid, buf->list); - retcode = -EINVAL; - goto cleanup; - } - /* This isn't a race condition on - buf->list, since our concern is the - buffer reclaim during the time the - process closes the /dev/drm? handle, so - it can't also be doing DMA. */ - buf->list = DRM_LIST_PRIO; - buf->used = d->send_sizes[i]; - buf->context = d->context; - buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; - address = (unsigned long)buf->address; - length = buf->used; - if (!length) { - DRM_ERROR("0 length buffer\n"); - } - if (buf->pending) { - DRM_ERROR("Sending pending buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; - } - if (buf->waiting) { - DRM_ERROR("Sending waiting buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - retcode = -EINVAL; - goto cleanup; + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + +static void i810EmitTexVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_TEX_SETUP_SIZE ); + + OUT_RING( GFX_OP_MAP_INFO ); + OUT_RING( code[I810_TEXREG_MI1] ); + OUT_RING( code[I810_TEXREG_MI2] ); + OUT_RING( code[I810_TEXREG_MI3] ); + + for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) + { + OUT_RING( tmp ); + j++; } - buf->pending = 1; + } - if (dev->last_context != buf->context - && !(dev->queuelist[buf->context]->flags - & _DRM_CONTEXT_PRESERVED)) { - add_wait_queue(&dev->context_wait, &entry); - current->state = TASK_INTERRUPTIBLE; - /* PRE: dev->last_context != buf->context */ - drm_context_switch(dev, dev->last_context, - buf->context); - /* POST: we will wait for the context - switch and will dispatch on a later call - when dev->last_context == buf->context. - NOTE WE HOLD THE LOCK THROUGHOUT THIS - TIME! */ - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&dev->context_wait, &entry); - if (signal_pending(current)) { - retcode = -EINTR; - goto cleanup; - } - if (dev->last_context != buf->context) { - DRM_ERROR("Context mismatch: %d %d\n", - dev->last_context, - buf->context); - } - } + if (j & 1) + OUT_RING( 0 ); -#if DRM_DMA_HISTOGRAM - buf->time_queued = get_cycles(); - buf->time_dispatched = buf->time_queued; -#endif - i810_dma_dispatch(dev, address, length); - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + ADVANCE_LP_RING(); +} - atomic_add(length, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - - if (last_buf) { - drm_free_buffer(dev, last_buf); - } - last_buf = buf; + +/* Need to do some additional checking when setting the dest buffer. + */ +static void i810EmitDestVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); + + tmp = code[I810_DESTREG_DI1]; + if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( tmp ); + } else + DRM_DEBUG("bad di1 %x (allow %x or %x)\n", + tmp, dev_priv->front_di1, dev_priv->back_di1); + + /* invarient: + */ + OUT_RING( CMD_OP_Z_BUFFER_INFO ); + OUT_RING( dev_priv->zi1 ); + + OUT_RING( GFX_OP_DESTBUFFER_VARS ); + OUT_RING( code[I810_DESTREG_DV1] ); + + OUT_RING( GFX_OP_DRAWRECT_INFO ); + OUT_RING( code[I810_DESTREG_DR1] ); + OUT_RING( code[I810_DESTREG_DR2] ); + OUT_RING( code[I810_DESTREG_DR3] ); + OUT_RING( code[I810_DESTREG_DR4] ); + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + + + +static void i810EmitState( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + if (dirty & I810_UPLOAD_BUFFERS) { + i810EmitDestVerified( dev, sarea_priv->BufferState ); + sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS; } + if (dirty & I810_UPLOAD_CTX) { + i810EmitContextVerified( dev, sarea_priv->ContextState ); + sarea_priv->dirty &= ~I810_UPLOAD_CTX; + } -cleanup: - if (last_buf) { - i810_dma_ready(dev); - drm_free_buffer(dev, last_buf); + if (dirty & I810_UPLOAD_TEX0) { + i810EmitTexVerified( dev, sarea_priv->TexState[0] ); + sarea_priv->dirty &= ~I810_UPLOAD_TEX0; } - - if (must_free && !dev->context_flag) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + + if (dirty & I810_UPLOAD_TEX1) { + i810EmitTexVerified( dev, sarea_priv->TexState[1] ); + sarea_priv->dirty &= ~I810_UPLOAD_TEX1; } - clear_bit(0, &dev->interrupt_flag); - return retcode; } -static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) + + +/* need to verify + */ +static void i810_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval ) { - DECLARE_WAITQUEUE(entry, current); - drm_buf_t *last_buf = NULL; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = 2; + int i; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox ; i++, pbox++) { + unsigned int x = pbox->x1; + unsigned int y = pbox->y1; + unsigned int width = (pbox->x2 - x) * cpp; + unsigned int height = pbox->y2 - y; + unsigned int start = y * pitch + x * cpp; + + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; - if (d->flags & _DRM_DMA_BLOCK) { - last_buf = dma->buflist[d->send_indices[d->send_count-1]]; - add_wait_queue(&last_buf->dma_wait, &entry); - } - - if ((retcode = drm_dma_enqueue(dev, d))) { - if (d->flags & _DRM_DMA_BLOCK) - remove_wait_queue(&last_buf->dma_wait, &entry); - return retcode; - } - - i810_dma_schedule(dev, 0); - - if (d->flags & _DRM_DMA_BLOCK) { - DRM_DEBUG("%d waiting\n", current->pid); - current->state = TASK_INTERRUPTIBLE; - for (;;) { - if (!last_buf->waiting - && !last_buf->pending) - break; /* finished */ - schedule(); - if (signal_pending(current)) { - retcode = -EINTR; /* Can't restart */ - break; - } + if ( flags & I810_FRONT ) { + DRM_DEBUG("clear front\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( start ); + OUT_RING( clear_color ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); } - current->state = TASK_RUNNING; - DRM_DEBUG("%d running\n", current->pid); - remove_wait_queue(&last_buf->dma_wait, &entry); - if (!retcode - || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { - if (!waitqueue_active(&last_buf->dma_wait)) { - drm_free_buffer(dev, last_buf); - } + + if ( flags & I810_BACK ) { + DRM_DEBUG("clear back\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( dev_priv->back_offset + start ); + OUT_RING( clear_color ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); } - if (retcode) { - DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", - d->context, - last_buf->waiting, - last_buf->pending, - DRM_WAITCOUNT(dev, d->context), - last_buf->idx, - last_buf->list, - last_buf->pid, - current->pid); + + if ( flags & I810_DEPTH ) { + DRM_DEBUG("clear depth\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( dev_priv->depth_offset + start ); + OUT_RING( clear_zval ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); } } - return retcode; } -int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static void i810_dma_dispatch_swap( drm_device_t *dev ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_dma_t d; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = 2; + int ofs = dev_priv->back_offset; + int i; + RING_LOCALS; + + DRM_DEBUG("swapbuffers\n"); + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox; i++, pbox++) + { + unsigned int w = pbox->x2 - pbox->x1; + unsigned int h = pbox->y2 - pbox->y1; + unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; + unsigned int start = ofs + dst; + + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox[i].x1, pbox[i].y1, + pbox[i].x2, pbox[i].y2); + + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); + OUT_RING( pitch | (0xCC << 16)); + OUT_RING( (h << 16) | (w * cpp)); + OUT_RING( dst ); + OUT_RING( pitch ); + OUT_RING( start ); + ADVANCE_LP_RING(); + } +} - printk("i810_dma start\n"); - copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); - DRM_DEBUG("%d %d: %d send, %d req\n", - current->pid, d.context, d.send_count, d.request_count); - if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { - DRM_ERROR("Process %d using context %d\n", - current->pid, d.context); - return -EINVAL; +static void i810_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, + int discard, + int used) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int i = 0, u; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + if (discard) { + u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, + I810_BUF_HARDWARE); + if(u != I810_BUF_CLIENT) { + DRM_DEBUG("xxxx 2\n"); + } } - if (d.send_count < 0 || d.send_count > dma->buf_count) { - DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", - current->pid, d.send_count, dma->buf_count); - return -EINVAL; + if (used > 4*1024) + used = 0; + + if (sarea_priv->dirty) + i810EmitState( dev ); + + DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", + address, used, nbox); + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : %lx\n", start); + DRM_DEBUG( "used : %d\n", used); + DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); + + if (buf_priv->currently_mapped == I810_BUF_MAPPED) { + *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); + + if (used & 4) { + *(u32 *)((u32)buf_priv->virtual + used) = 0; + used += 4; + } + + i810_unmap_buffer(buf); } - if (d.request_count < 0 || d.request_count > dma->buf_count) { - DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - current->pid, d.request_count, dma->buf_count); - return -EINVAL; + + if (used) { + do { + if (i < nbox) { + BEGIN_LP_RING(4); + OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | + SC_ENABLE ); + OUT_RING( GFX_OP_SCISSOR_INFO ); + OUT_RING( box[i].x1 | (box[i].y1<<16) ); + OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) ); + ADVANCE_LP_RING(); + } + + BEGIN_LP_RING(4); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + } while (++i < nbox); } - if (d.send_count) { -#if 0 - if (d.flags & _DRM_DMA_PRIORITY) - retcode = i810_dma_priority(dev, &d); - else - retcode = i810_dma_send_buffers(dev, &d); -#endif - printk("i810_dma priority\n"); - - retcode = i810_dma_priority(dev, &d); + BEGIN_LP_RING(10); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( 0 ); + + if (discard) { + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( 0 ); } - d.granted_count = 0; + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} - if (!retcode && d.request_count) { - retcode = drm_dma_get_buffers(dev, &d); - } - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, d.granted_count); - copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); +/* Interrupts are only for flushing */ +static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + u16 temp; + + atomic_inc(&dev->total_irq); + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + else + return; + + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void i810_dma_task_queue(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - printk("i810_dma end (granted)\n"); - return retcode; + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); } int i810_irq_install(drm_device_t *dev, int irq) { int retcode; - + u16 temp; + if (!irq) return -EINVAL; down(&dev->struct_sem); @@ -591,6 +890,7 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); + DRM_DEBUG( "Interrupt Install : %d\n", irq); DRM_DEBUG("%d\n", irq); dev->context_flag = 0; @@ -603,16 +903,25 @@ int i810_irq_install(drm_device_t *dev, int irq) dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = i810_dma_schedule_tq_wrapper; + dev->tq.routine = i810_dma_task_queue; dev->tq.data = dev; - /* Before installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_HWSTAM); + temp = temp & 0x6000; + I810_WRITE16(I810REG_HWSTAM, temp); + + temp = I810_READ16(I810REG_INT_MASK_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */ + /* Install handler */ if ((retcode = request_irq(dev->irq, i810_dma_service, - 0, + SA_SHIRQ, dev->devname, dev))) { down(&dev->struct_sem); @@ -620,15 +929,21 @@ int i810_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - - /* After installing handler */ - /* TODO */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + temp = temp | 0x0003; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Enable bp & user interrupts */ return 0; } int i810_irq_uninstall(drm_device_t *dev) { int irq; + u16 temp; + + +/* return 0; */ down(&dev->struct_sem); irq = dev->irq; @@ -636,16 +951,25 @@ int i810_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - + + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); DRM_DEBUG("%d\n", irq); - - /* TODO : Disable interrupts */ + + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Disable all interrupts */ + free_irq(irq, dev); return 0; } - int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -654,8 +978,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; int retcode; - printk(KERN_INFO "i810_control\n"); - i810_dma_init(dev); + DRM_DEBUG( "i810_control\n"); copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); @@ -674,20 +997,161 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } +static inline void i810_dma_emit_flush(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + +/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */ +/* atomic_set(&dev_priv->flush_done, 1); */ +/* wake_up_interruptible(&dev_priv->flush_queue); */ +} + +static inline void i810_dma_quiescent_emit(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(4); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + +/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */ +/* atomic_set(&dev_priv->flush_done, 1); */ +/* wake_up_interruptible(&dev_priv->flush_queue); */ +} + +static void i810_dma_quiescent(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + + if(dev_priv == NULL) { + return; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + + for (;;) { + i810_dma_quiescent_emit(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return; +} + +static int i810_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + unsigned long end; + int i, ret = 0; + + if(dev_priv == NULL) { + return 0; + } + atomic_set(&dev_priv->flush_done, 0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + for (;;) { + i810_dma_emit_flush(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, + I810_BUF_FREE); + + if (used == I810_BUF_HARDWARE) + DRM_DEBUG("reclaimed from HARDWARE\n"); + if (used == I810_BUF_CLIENT) + DRM_DEBUG("still on client HARDWARE\n"); + } + + return ret; +} + +/* Must be called with the lock held */ +void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if (!dev->dev_private) return; + if (!dma->buflist) return; + + i810_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid && buf_priv) { + int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, + I810_BUF_FREE); + + if (used == I810_BUF_CLIENT) + DRM_DEBUG("reclaimed from client\n"); + if(buf_priv->currently_mapped == I810_BUF_MAPPED) + buf_priv->currently_mapped = I810_BUF_UNMAPPED; + } + } +} + int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); int ret = 0; drm_lock_t lock; - drm_queue_t *q; -#if DRM_DMA_HISTOGRAM - cycles_t start; - - dev->lck_start = start = get_cycles(); -#endif copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); @@ -696,26 +1160,18 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->pid, lock.context); return -EINVAL; } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); - if (lock.context < 0 || lock.context >= dev->queue_count) { + if (lock.context < 0) { return -EINVAL; } - q = dev->queuelist[lock.context]; - - ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + /* Only one queue: + */ if (!ret) { - if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) - != lock.context) { - long j = jiffies - dev->lock.lock_time; - - if (j > 0 && j <= DRM_LOCK_SLICE) { - /* Can't take lock if we just had it and - there is contention. */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(j); - } - } add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { if (!dev->lock.hw_lock) { @@ -728,13 +1184,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, dev->lock.pid = current->pid; dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); - atomic_inc(&q->total_locks); break; /* Got lock */ } /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; + DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -744,19 +1200,153 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->state = TASK_RUNNING; remove_wait_queue(&dev->lock.lock_queue, &entry); } - - drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ if (!ret) { - if (lock.flags & _DRM_LOCK_READY) - i810_dma_ready(dev); - if (lock.flags & _DRM_LOCK_QUIESCENT) - i810_dma_quiescent(dev); + if (lock.flags & _DRM_LOCK_QUIESCENT) { + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + DRM_DEBUG("fred\n"); + i810_dma_quiescent(dev); + } } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + return ret; +} + +int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("i810_flush_ioctl\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + i810_flush_queue(dev); + return 0; +} + + +int i810_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_i810_vertex_t vertex; + + copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + i810_dma_dispatch_vertex( dev, + dma->buflist[ vertex.idx ], + vertex.discard, vertex.used ); -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif + atomic_add(vertex.used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + + + +int i810_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_clear_t clear; + + copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_clear_bufs called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + return 0; +} + +int i810_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("i810_swap_bufs\n"); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_swap_buf called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_swap( dev ); + return 0; +} + +int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + sarea_priv->last_dispatch = (int) hw_status[5]; + return 0; +} + +int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_i810_dma_t d; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + DRM_DEBUG("getbuf\n"); + copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma called without lock held\n"); + return -EINVAL; + } - return ret; + d.granted = 0; + + retcode = i810_dma_get_buffer(dev, &d, filp); + + DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", + current->pid, retcode, d.granted); + + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; } diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drm.h new file mode 100644 index 000000000..4c8e09f6a --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drm.h @@ -0,0 +1,188 @@ +#ifndef _I810_DRM_H_ +#define _I810_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ + +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER) +#define I810_DMA_BUF_NR 256 +#define I810_NR_SAREA_CLIPRECTS 8 + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define I810_NR_TEX_REGIONS 64 +#define I810_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +#define I810_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define I810_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define I810_UPLOAD_CTX 0x4 +#define I810_UPLOAD_BUFFERS 0x8 +#define I810_UPLOAD_TEX0 0x10 +#define I810_UPLOAD_TEX1 0x20 +#define I810_UPLOAD_CLIPRECTS 0x40 + + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +/* Destbuffer state + * - backbuffer linear offset and pitch -- invarient in the current dri + * - zbuffer linear offset and pitch -- also invarient + * - drawing origin in back and depth buffers. + * + * Keep the depth/back buffer state here to acommodate private buffers + * in the future. + */ +#define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */ +#define I810_DESTREG_DI1 1 +#define I810_DESTREG_DV0 2 /* GFX_OP_DESTBUFFER_VARS (2 dwords) */ +#define I810_DESTREG_DV1 3 +#define I810_DESTREG_DR0 4 /* GFX_OP_DRAWRECT_INFO (4 dwords) */ +#define I810_DESTREG_DR1 5 +#define I810_DESTREG_DR2 6 +#define I810_DESTREG_DR3 7 +#define I810_DESTREG_DR4 8 +#define I810_DEST_SETUP_SIZE 10 + +/* Context state + */ +#define I810_CTXREG_CF0 0 /* GFX_OP_COLOR_FACTOR */ +#define I810_CTXREG_CF1 1 +#define I810_CTXREG_ST0 2 /* GFX_OP_STIPPLE */ +#define I810_CTXREG_ST1 3 +#define I810_CTXREG_VF 4 /* GFX_OP_VERTEX_FMT */ +#define I810_CTXREG_MT 5 /* GFX_OP_MAP_TEXELS */ +#define I810_CTXREG_MC0 6 /* GFX_OP_MAP_COLOR_STAGES - stage 0 */ +#define I810_CTXREG_MC1 7 /* GFX_OP_MAP_COLOR_STAGES - stage 1 */ +#define I810_CTXREG_MC2 8 /* GFX_OP_MAP_COLOR_STAGES - stage 2 */ +#define I810_CTXREG_MA0 9 /* GFX_OP_MAP_ALPHA_STAGES - stage 0 */ +#define I810_CTXREG_MA1 10 /* GFX_OP_MAP_ALPHA_STAGES - stage 1 */ +#define I810_CTXREG_MA2 11 /* GFX_OP_MAP_ALPHA_STAGES - stage 2 */ +#define I810_CTXREG_SDM 12 /* GFX_OP_SRC_DEST_MONO */ +#define I810_CTXREG_FOG 13 /* GFX_OP_FOG_COLOR */ +#define I810_CTXREG_B1 14 /* GFX_OP_BOOL_1 */ +#define I810_CTXREG_B2 15 /* GFX_OP_BOOL_2 */ +#define I810_CTXREG_LCS 16 /* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */ +#define I810_CTXREG_PV 17 /* GFX_OP_PV_RULE -- Invarient! */ +#define I810_CTXREG_ZA 18 /* GFX_OP_ZBIAS_ALPHAFUNC */ +#define I810_CTXREG_AA 19 /* GFX_OP_ANTIALIAS */ +#define I810_CTX_SETUP_SIZE 20 + +/* Texture state (per tex unit) + */ +#define I810_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (4 dwords) */ +#define I810_TEXREG_MI1 1 +#define I810_TEXREG_MI2 2 +#define I810_TEXREG_MI3 3 +#define I810_TEXREG_MF 4 /* GFX_OP_MAP_FILTER */ +#define I810_TEXREG_MLC 5 /* GFX_OP_MAP_LOD_CTL */ +#define I810_TEXREG_MLL 6 /* GFX_OP_MAP_LOD_LIMITS */ +#define I810_TEXREG_MCS 7 /* GFX_OP_MAP_COORD_SETS ??? */ +#define I810_TEX_SETUP_SIZE 8 + +#define I810_FRONT 0x1 +#define I810_BACK 0x2 +#define I810_DEPTH 0x4 + + +typedef struct _drm_i810_init { + enum { + I810_INIT_DMA = 0x01, + I810_CLEANUP_DMA = 0x02 + } func; + int ring_map_idx; + int buffer_map_idx; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; +} drm_i810_init_t; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +typedef struct _drm_i810_tex_region { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char in_use; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} drm_i810_tex_region_t; + +typedef struct _drm_i810_sarea { + unsigned int ContextState[I810_CTX_SETUP_SIZE]; + unsigned int BufferState[I810_DEST_SETUP_SIZE]; + unsigned int TexState[2][I810_TEX_SETUP_SIZE]; + unsigned int dirty; + + unsigned int nbox; + drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS]; + + /* Maintain an LRU of contiguous regions of texture space. If + * you think you own a region of texture memory, and it has an + * age different to the one you set, then you are mistaken and + * it has been stolen by another client. If global texAge + * hasn't changed, there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained + * texture information of other clients - by maintaining them + * in the same lru which is used to age their own textures, + * clients have an approximate lru for the whole of global + * texture space, and can make informed decisions as to which + * areas to kick out. There is no need to choose whether to + * kick out your own texture or someone else's - simply eject + * them all in LRU order. + */ + + drm_i810_tex_region_t texList[I810_NR_TEX_REGIONS+1]; + /* Last elt is sentinal */ + int texAge; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int last_quiescent; /* */ + int ctxOwner; /* last context to upload state */ + + int vertex_prim; + +} drm_i810_sarea_t; + +typedef struct _drm_i810_clear { + int clear_color; + int clear_depth; + int flags; +} drm_i810_clear_t; + + + +/* These may be placeholders if we have more cliprects than + * I810_NR_SAREA_CLIPRECTS. In that case, the client sets discard to + * false, indicating that the buffer will be dispatched again with a + * new set of cliprects. + */ +typedef struct _drm_i810_vertex { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int discard; /* client is finished with the buffer? */ +} drm_i810_vertex_t; + +typedef struct drm_i810_dma { + void *virtual; + int request_idx; + int request_size; + int granted; +} drm_i810_dma_t; + +#endif /* _I810_DRM_H_ */ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.c index f33153a36..75b402daa 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.c @@ -33,11 +33,13 @@ #define EXPORT_SYMTAB #include "drmP.h" #include "i810_drv.h" + + EXPORT_SYMBOL(i810_init); EXPORT_SYMBOL(i810_cleanup); #define I810_NAME "i810" -#define I810_DESC "Matrox g200/g400" +#define I810_DESC "Intel I810" #define I810_DATE "19991213" #define I810_MAJOR 0 #define I810_MINOR 0 @@ -54,6 +56,7 @@ static struct file_operations i810_fops = { mmap: drm_mmap, read: drm_read, fasync: drm_fasync, + poll: drm_poll, }; static struct miscdevice i810_misc = { @@ -77,21 +80,18 @@ static drm_ioctl_desc_t i810_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { i810_addbufs, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { i810_markbufs, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { i810_infobufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { i810_mapbufs, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { i810_freebufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { i810_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { i810_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { i810_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { i810_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { i810_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { i810_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { i810_resctx, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { i810_dma, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { i810_lock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { i810_unlock, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, @@ -104,6 +104,14 @@ static drm_ioctl_desc_t i810_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)] = { i810_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl,1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, }; #define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls) @@ -121,7 +129,7 @@ MODULE_PARM(i810, "s"); int init_module(void) { - printk("doing i810_init()\n"); + DRM_DEBUG("doing i810_init()\n"); return i810_init(); } @@ -364,7 +372,7 @@ int i810_init(void) #ifdef MODULE drm_parse_options(i810); #endif - printk("doing misc_register\n"); + DRM_DEBUG("doing misc_register\n"); if ((retcode = misc_register(&i810_misc))) { DRM_ERROR("Cannot register \"%s\"\n", I810_NAME); return retcode; @@ -372,13 +380,22 @@ int i810_init(void) dev->device = MKDEV(MISC_MAJOR, i810_misc.minor); dev->name = I810_NAME; - printk("doing mem init\n"); + DRM_DEBUG("doing mem init\n"); drm_mem_init(); - printk("doing proc init\n"); + DRM_DEBUG("doing proc init\n"); drm_proc_init(dev); - printk("doing agp init\n"); + DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); - printk("doing ctxbitmap init\n"); + if(dev->agp == NULL) { + DRM_INFO("The i810 drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the i810 module\n"); + drm_proc_cleanup(); + misc_deregister(&i810_misc); + i810_takedown(dev); + return -ENOMEM; + } + DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); drm_proc_cleanup(); @@ -386,10 +403,6 @@ int i810_init(void) i810_takedown(dev); return retcode; } -#if 0 - printk("doing i810_dma_init\n"); - i810_dma_init(dev); -#endif DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", I810_NAME, @@ -417,7 +430,6 @@ void i810_cleanup(void) DRM_INFO("Module unloaded\n"); } drm_ctxbitmap_cleanup(dev); - i810_dma_cleanup(dev); i810_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -484,24 +496,82 @@ int i810_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + i810_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return i810_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + i810_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } + } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return i810_takedown(dev); } + spin_unlock(&dev->count_lock); return retcode; } @@ -566,8 +636,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd, atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); - i810_dma_schedule(dev, 1); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); if (!dev->context_flag) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.h index 0f5f42bb6..334cacb2a 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_drv.h @@ -32,6 +32,50 @@ #ifndef _I810_DRV_H_ #define _I810_DRV_H_ +typedef struct drm_i810_buf_priv { + u32 *in_use; + int my_use_idx; + int currently_mapped; + void *virtual; + void *kernel_virtual; + int map_count; + struct vm_area_struct *vma; +} drm_i810_buf_priv_t; + +typedef struct _drm_i810_ring_buffer{ + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; +} drm_i810_ring_buffer_t; + +typedef struct drm_i810_private { + int ring_map_idx; + int buffer_map_idx; + + drm_i810_ring_buffer_t ring; + drm_i810_sarea_t *sarea_priv; + + unsigned long hw_status_page; + unsigned long counter; + + atomic_t flush_done; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + drm_buf_t *mmap_buffer; + + + u32 front_di1, back_di1, zi1; + + int back_offset; + int depth_offset; + int w, h; + int pitch; +} drm_i810_private_t; + /* i810_drv.c */ extern int i810_init(void); extern void i810_cleanup(void); @@ -46,16 +90,22 @@ extern int i810_unlock(struct inode *inode, struct file *filp, /* i810_dma.c */ extern int i810_dma_schedule(drm_device_t *dev, int locked); -extern int i810_dma(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int i810_getbuf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int i810_irq_install(drm_device_t *dev, int irq); extern int i810_irq_uninstall(drm_device_t *dev); extern int i810_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i810_dma_init(drm_device_t *dev); -extern void i810_dma_cleanup(drm_device_t *dev); +extern int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); /* i810_bufs.c */ @@ -67,10 +117,108 @@ extern int i810_markbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int i810_mapbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern int i810_addmap(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + /* i810_context.c */ +extern int i810_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i810_context_switch(drm_device_t *dev, int old, int new); +extern int i810_context_switch_complete(drm_device_t *dev, int new); + +#define I810_VERBOSE 0 + + +int i810_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I810REG_HWSTAM 0x02098 +#define I810REG_INT_IDENTITY_R 0x020a4 +#define I810REG_INT_MASK_R 0x020a8 +#define I810REG_INT_ENABLE_R 0x020a0 + +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) + +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x2) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24)) + +#define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23)) +#define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23)) + +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR13_SOLID_PATTERN 0x80000000 + + #endif + diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c index 2e24e5b48..fe6a7b525 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c @@ -25,17 +25,15 @@ * * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com> * Jeff Hartmann <jhartmann@precisioninsight.com> + * Keith Whitwell <keithw@precisioninsight.com> * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_dma.c,v 1.1 2000/02/11 17:26:07 dawes Exp $ + * $XFree86$ * */ #define __NO_VERSION__ #include "drmP.h" #include "mga_drv.h" -#include "mgareg_flags.h" -#include "mga_dma.h" -#include "mga_state.h" #include <linux/interrupt.h> /* For task queue support */ @@ -48,643 +46,575 @@ #define MGA_WRITE(reg,val) do { MGA_DEREF(reg) = val; } while (0) #define PDEA_pagpxfer_enable 0x2 -#define MGA_SYNC_TAG 0x423f4200 -typedef enum { - TT_GENERAL, - TT_BLIT, - TT_VECTOR, - TT_VERTEX -} transferType_t; +static int mga_flush_queue(drm_device_t *dev); - -static void mga_delay(void) +static unsigned long mga_alloc_page(drm_device_t *dev) { - return; + unsigned long address; + + DRM_DEBUG("%s\n", __FUNCTION__); + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) { + return 0; + } + atomic_inc(&mem_map[MAP_NR((void *) address)].count); + set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); + + return address; } -int mga_dma_cleanup(drm_device_t *dev) +static void mga_free_page(drm_device_t *dev, unsigned long page) { - if(dev->dev_private) { - drm_mga_private_t *dev_priv = - (drm_mga_private_t *) dev->dev_private; - - if(dev_priv->ioremap) { - int temp = (dev_priv->warp_ucode_size + - dev_priv->primary_size + - PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + DRM_DEBUG("%s\n", __FUNCTION__); - drm_ioremapfree((void *) dev_priv->ioremap, temp); - } - - drm_free(dev->dev_private, sizeof(drm_mga_private_t), - DRM_MEM_DRIVER); - dev->dev_private = NULL; + if(page == 0UL) { + return; } - - return 0; + atomic_dec(&mem_map[MAP_NR((void *) page)].count); + clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); + wake_up(&mem_map[MAP_NR((void *) page)].wait); + free_page(page); + return; } -static int mga_alloc_kernel_queue(drm_device_t *dev) +static void mga_delay(void) { - drm_queue_t *queue = NULL; - /* Allocate a new queue */ - down(&dev->struct_sem); - - if(dev->queue_count != 0) { - /* Reseting the kernel context here is not - * a race, since it can only happen when that - * queue is empty. - */ - queue = dev->queuelist[DRM_KERNEL_CONTEXT]; - printk("Kernel queue already allocated\n"); - } else { - queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); - if(!queue) { - up(&dev->struct_sem); - printk("out of memory\n"); - return -ENOMEM; - } - ++dev->queue_count; - dev->queuelist = drm_alloc(sizeof(*dev->queuelist), - DRM_MEM_QUEUES); - if(!dev->queuelist) { - up(&dev->struct_sem); - drm_free(queue, sizeof(*queue), DRM_MEM_QUEUES); - printk("out of memory\n"); - return -ENOMEM; - } - } - - memset(queue, 0, sizeof(*queue)); - atomic_set(&queue->use_count, 1); - atomic_set(&queue->finalization, 0); - atomic_set(&queue->block_count, 0); - atomic_set(&queue->block_read, 0); - atomic_set(&queue->block_write, 0); - atomic_set(&queue->total_queued, 0); - atomic_set(&queue->total_flushed, 0); - atomic_set(&queue->total_locks, 0); - - init_waitqueue_head(&queue->write_queue); - init_waitqueue_head(&queue->read_queue); - init_waitqueue_head(&queue->flush_queue); - - queue->flags = 0; - - drm_waitlist_create(&queue->waitlist, dev->dma->buf_count); - - dev->queue_slots = 1; - dev->queuelist[DRM_KERNEL_CONTEXT] = queue; - dev->queue_count--; - - up(&dev->struct_sem); - printk("%d (new)\n", dev->queue_count - 1); - return DRM_KERNEL_CONTEXT; + return; } -static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { - drm_mga_private_t *dev_priv; - drm_map_t *prim_map = NULL; - drm_map_t *sarea_map = NULL; - int temp; +void mga_flush_write_combine(void) +{ + int xchangeDummy; + DRM_DEBUG("%s\n", __FUNCTION__); + __asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy)); + __asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;" + " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;" + " pop %%eax" : /* no outputs */ : /* no inputs */ ); +} - dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); - if(dev_priv == NULL) return -ENOMEM; - dev->dev_private = (void *) dev_priv; +/* These are two age tags that will never be sent to + * the hardware */ +#define MGA_BUF_USED 0xffffffff +#define MGA_BUF_FREE 0 - printk("dev_private\n"); +static int mga_freelist_init(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + int i; - memset(dev_priv, 0, sizeof(drm_mga_private_t)); - atomic_set(&dev_priv->pending_bufs, 0); + DRM_DEBUG("%s\n", __FUNCTION__); - if((init->reserved_map_idx >= dev->map_count) || - (init->buffer_map_idx >= dev->map_count)) { - mga_dma_cleanup(dev); - printk("reserved_map or buffer_map are invalid\n"); - return -EINVAL; - } + dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + if(dev_priv->head == NULL) return -ENOMEM; + memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); + dev_priv->head->age = MGA_BUF_USED; - if(mga_alloc_kernel_queue(dev) != DRM_KERNEL_CONTEXT) { - mga_dma_cleanup(dev); - DRM_ERROR("Kernel context queue not present\n"); + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + item = drm_alloc(sizeof(drm_mga_freelist_t), + DRM_MEM_DRIVER); + if(item == NULL) return -ENOMEM; + memset(item, 0, sizeof(drm_mga_freelist_t)); + item->age = MGA_BUF_FREE; + item->prev = dev_priv->head; + item->next = dev_priv->head->next; + if(dev_priv->head->next != NULL) + dev_priv->head->next->prev = item; + if(item->next == NULL) dev_priv->tail = item; + item->buf = buf; + buf_priv->my_freelist = item; + buf_priv->discard = 0; + buf_priv->dispatched = 0; + dev_priv->head->next = item; } - - dev_priv->reserved_map_idx = init->reserved_map_idx; - dev_priv->buffer_map_idx = init->buffer_map_idx; - sarea_map = dev->maplist[0]; - dev_priv->sarea_priv = (drm_mga_sarea_t *) - ((u8 *)sarea_map->handle + - init->sarea_priv_offset); - printk("sarea_priv\n"); - - /* Scale primary size to the next page */ - dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / - PAGE_SIZE) * PAGE_SIZE; - dev_priv->warp_ucode_size = init->warp_ucode_size; - dev_priv->chipset = init->chipset; - dev_priv->fbOffset = init->fbOffset; - dev_priv->backOffset = init->backOffset; - dev_priv->depthOffset = init->depthOffset; - dev_priv->textureOffset = init->textureOffset; - dev_priv->textureSize = init->textureSize; - dev_priv->cpp = init->cpp; - dev_priv->sgram = init->sgram; - dev_priv->stride = init->stride; - - dev_priv->frontOrg = init->frontOrg; - dev_priv->backOrg = init->backOrg; - dev_priv->depthOrg = init->depthOrg; - dev_priv->mAccess = init->mAccess; - - printk("memcpy\n"); - memcpy(&dev_priv->WarpIndex, &init->WarpIndex, - sizeof(mgaWarpIndex) * MGA_MAX_WARP_PIPES); - printk("memcpy done\n"); - prim_map = dev->maplist[init->reserved_map_idx]; - dev_priv->prim_phys_head = dev->agp->base + init->reserved_map_agpstart; - temp = init->warp_ucode_size + dev_priv->primary_size; - temp = ((temp + PAGE_SIZE - 1) / - PAGE_SIZE) * PAGE_SIZE; - printk("temp : %x\n", temp); - printk("dev->agp->base: %lx\n", dev->agp->base); - printk("init->reserved_map_agpstart: %x\n", init->reserved_map_agpstart); - - - dev_priv->ioremap = drm_ioremap(dev->agp->base + init->reserved_map_agpstart, - temp); - if(dev_priv->ioremap == NULL) { - printk("Ioremap failed\n"); - mga_dma_cleanup(dev); - return -ENOMEM; - } - - + return 0; +} - dev_priv->prim_head = (u32 *)dev_priv->ioremap; - printk("dev_priv->prim_head : %p\n", dev_priv->prim_head); - dev_priv->current_dma_ptr = dev_priv->prim_head; - dev_priv->prim_num_dwords = 0; - dev_priv->prim_max_dwords = dev_priv->primary_size / 4; - - printk("dma initialization\n"); +static void mga_freelist_cleanup(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + drm_mga_freelist_t *prev; - /* Private is now filled in, initialize the hardware */ - { - PRIMLOCALS; - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE( dev_priv ); + DRM_DEBUG("%s\n", __FUNCTION__); - /* Poll for the first buffer to insure that - * the status register will be correct - */ - printk("phys_head : %lx\n", phys_head); + item = dev_priv->head; + while(item) { + prev = item; + item = item->next; + drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + } - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); + dev_priv->head = dev_priv->tail = NULL; +} - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) { - int i; - for(i = 0 ; i < 4096; i++) mga_delay(); +/* Frees dispatch lock */ +static inline void mga_dma_quiescent(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long end; + int i; + + DRM_DEBUG("%s\n", __FUNCTION__); + end = jiffies + (HZ*3); + while(1) { + if(!test_and_set_bit(MGA_IN_DISPATCH, + &dev_priv->dispatch_status)) { + break; } - - MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); - - MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | - PDEA_pagpxfer_enable)); - - while(MGA_READ(MGAREG_DWGSYNC) == MGA_SYNC_TAG) { - int i; - for(i = 0; i < 4096; i++) mga_delay(); + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup\n"); + goto out_nolock; } + for (i = 0 ; i < 2000 ; i++) mga_delay(); + } + end = jiffies + (HZ*3); + DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS)); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup\n"); + goto out_status; + } + for (i = 0 ; i < 2000 ; i++) mga_delay(); + } + sarea_priv->dirty |= MGA_DMA_FLUSH; +out_status: + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); +out_nolock: +} + +static void mga_reset_freelist(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + int i; + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + buf_priv->my_freelist->age = MGA_BUF_FREE; } - - printk("dma init was successful\n"); - return 0; } -int mga_dma_init(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +/* Least recently used : + * These operations are not atomic b/c they are protected by the + * hardware lock */ + +drm_buf_t *mga_freelist_get(drm_device_t *dev) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_mga_init_t init; + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_freelist_t *prev; + drm_mga_freelist_t *next; + static int failed = 0; + + DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__, + dev_priv->tail->age, dev_priv->last_prim_age); - copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) { + DRM_DEBUG("I'm waiting on the freelist!!! %d\n", + dev_priv->last_prim_age); + set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->buf_queue, &entry); + for (;;) { + mga_dma_schedule(dev, 0); + if(!test_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status)) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + clear_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status); + goto failed_getbuf; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->buf_queue, &entry); + } - switch(init.func) { - case MGA_INIT_DMA: - return mga_dma_initialize(dev, &init); - case MGA_CLEANUP_DMA: - return mga_dma_cleanup(dev); + if(dev_priv->tail->age < dev_priv->last_prim_age) { + prev = dev_priv->tail->prev; + next = dev_priv->tail; + prev->next = NULL; + next->prev = next->next = NULL; + dev_priv->tail = prev; + next->age = MGA_BUF_USED; + failed = 0; + return next->buf; } - return -EINVAL; +failed_getbuf: + failed++; + return NULL; } -#define MGA_ILOAD_CMD (DC_opcod_iload | DC_atype_rpl | \ - DC_linear_linear | DC_bltmod_bfcol | \ - (0xC << DC_bop_SHIFT) | DC_sgnzero_enable | \ - DC_shftzero_enable | DC_clipdis_enable) - -static void __mga_iload_small(drm_device_t *dev, - drm_buf_t *buf, - int use_agp) +int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int y1 = buf_priv->boxes[0].y1; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); + drm_mga_freelist_t *prev; + drm_mga_freelist_t *head; + drm_mga_freelist_t *next; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(buf_priv->my_freelist->age == MGA_BUF_USED) { + /* Discarded buffer, put it on the tail */ + next = buf_priv->my_freelist; + next->age = MGA_BUF_FREE; + prev = dev_priv->tail; + prev->next = next; + next->prev = prev; + next->next = NULL; + dev_priv->tail = next; + DRM_DEBUG("Discarded\n"); + } else { + /* Normally aged buffer, put it on the head + 1, + * as the real head is a sentinal element + */ + next = buf_priv->my_freelist; + head = dev_priv->head; + prev = head->next; + head->next = next; + prev->prev = next; + next->prev = head; + next->next = prev; + } - PRIMOUTREG(MGAREG_DSTORG, dstorg | use_agp); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, (1 << 15)); - PRIMOUTREG(MGAREG_YDST, y1 * (x2 - x1)); - PRIMOUTREG(MGAREG_LEN, 1); - PRIMOUTREG(MGAREG_FXBNDRY, ((x2 - x1) * (y2 - y1) - 1) << 16); - PRIMOUTREG(MGAREG_AR0, (x2 - x1) * (y2 - y1) - 1); - PRIMOUTREG(MGAREG_AR3, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, address | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, (address + length) | use_agp); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + return 0; } -static void __mga_iload_xy(drm_device_t *dev, - drm_buf_t *buf, - int use_agp) +static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) { - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int y1 = buf_priv->boxes[0].y1; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - int pitch = buf_priv->ServerState[MGA_2DREG_PITCH]; - int width, height; - int texperdword = 0; - PRIMLOCALS; - - width = (x2 - x1); - height = (y2 - y1); - switch((maccess & 0x00000003)) { - case 0: - texperdword = 4; - break; - case 1: - texperdword = 2; - break; - case 2: - texperdword = 1; - break; - default: - DRM_ERROR("Invalid maccess value passed to __mga_iload_xy\n"); - return; + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + int i, temp, size_of_buf; + int offset = init->reserved_map_agpstart; + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / + PAGE_SIZE) * PAGE_SIZE; + size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; + dev_priv->warp_ucode_size = init->warp_ucode_size; + dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + if(dev_priv->prim_bufs == NULL) { + DRM_ERROR("Unable to allocate memory for prim_buf\n"); + return -ENOMEM; } + memset(dev_priv->prim_bufs, + 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); - x2 = x1 + width; - x2 = (x2 + (texperdword - 1)) & ~(texperdword - 1); - x1 = (x1 + (texperdword - 1)) & ~(texperdword - 1); - width = x2 - x1; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_DSTORG, dstorg | use_agp); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, pitch); - PRIMOUTREG(MGAREG_YDSTLEN, (y1 << 16) | height); - - PRIMOUTREG(MGAREG_FXBNDRY, ((x1+width-1) << 16) | x1); - PRIMOUTREG(MGAREG_AR0, width * height - 1); - PRIMOUTREG(MGAREG_AR3, 0 ); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, address | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, (address + length) | use_agp); + temp = init->warp_ucode_size + dev_priv->primary_size; + temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, + temp); + if(dev_priv->ioremap == NULL) { + DRM_DEBUG("Ioremap failed\n"); + return -ENOMEM; + } + init_waitqueue_head(&dev_priv->wait_queue); + + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + if(prim_buffer == NULL) return -ENOMEM; + memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); + prim_buffer->phys_head = offset + dev->agp->base; + prim_buffer->current_dma_ptr = + prim_buffer->head = + (u32 *) (dev_priv->ioremap + + offset - + init->reserved_map_agpstart); + prim_buffer->num_dwords = 0; + prim_buffer->max_dwords = size_of_buf / sizeof(u32); + prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ + prim_buffer->sec_used = 0; + prim_buffer->idx = i; + prim_buffer->prim_age = i + 1; + offset = offset + size_of_buf; + dev_priv->prim_bufs[i] = prim_buffer; + } + dev_priv->current_prim_idx = 0; + dev_priv->next_prim = + dev_priv->last_prim = + dev_priv->current_prim = + dev_priv->prim_bufs[0]; + dev_priv->next_prim_age = 2; + dev_priv->last_prim_age = 1; + set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status); + return 0; } -static void mga_dma_dispatch_iload(drm_device_t *dev, drm_buf_t *buf) +void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) { - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - - int use_agp = PDEA_pagpxfer_enable; - int x1 = buf_priv->boxes[0].x1; - int x2 = buf_priv->boxes[0].x2; + drm_mga_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int use_agp = PDEA_pagpxfer_enable; + unsigned long end; + int i; + int next_idx; + PRIMLOCALS; + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->last_prim = prim; - if((x2 - x1) < 32) { - printk("using iload small\n"); - __mga_iload_small(dev, buf, use_agp); + /* We never check for overflow, b/c there is always room */ + PRIMPTR(prim); + if(num_dwords <= 0) { + DRM_DEBUG("num_dwords == 0 when dispatched\n"); + goto out_prim_wait; + } + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMFINISH(prim); + + end = jiffies + (HZ*3); + if(sarea_priv->dirty & MGA_DMA_FLUSH) { + DRM_DEBUG("Dma top flush\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Dma Top Flush)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } + sarea_priv->dirty &= ~(MGA_DMA_FLUSH); } else { - printk("using iload xy\n"); - __mga_iload_xy(dev, buf, use_agp); - } -} - -static void mga_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf) -{ - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int use_agp = PDEA_pagpxfer_enable; - int i, count; - PRIMLOCALS; - - PRIMRESET(dev_priv); - - count = buf_priv->nbox; - if (count == 0) - count = 1; - - mgaEmitState( dev_priv, buf_priv ); - - for (i = 0 ; i < count ; i++) { - if (i < buf_priv->nbox) - mgaEmitClipRect( dev_priv, &buf_priv->boxes[i] ); - - PRIMGETPTR(dev_priv); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, address | TT_VERTEX); - PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); + DRM_DEBUG("Status wait\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Status Wait)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } } - PRIMGETPTR( dev_priv ); - - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + mga_flush_write_combine(); + atomic_inc(&dev_priv->pending_bufs); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + prim->num_dwords = 0; + sarea_priv->last_enqueue = prim->prim_age; + + next_idx = prim->idx + 1; + if(next_idx >= MGA_NUM_PRIM_BUFS) + next_idx = 0; + + dev_priv->next_prim = dev_priv->prim_bufs[next_idx]; + return; + + out_prim_wait: + prim->num_dwords = 0; + prim->sec_used = 0; + clear_bit(MGA_BUF_IN_USE, &prim->buffer_status); + wake_up_interruptible(&dev_priv->wait_queue); + clear_bit(MGA_BUF_SWAP_PENDING, &prim->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } - -/* Used internally for the small buffers generated from client state - * information. - */ -static void mga_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf) +int mga_advance_primary(drm_device_t *dev) { + DECLARE_WAITQUEUE(entry, current); drm_mga_private_t *dev_priv = dev->dev_private; - unsigned long address = (unsigned long)buf->bus_address; - int length = buf->used; - int use_agp = PDEA_pagpxfer_enable; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, address | TT_GENERAL); - PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); + drm_mga_prim_buf_t *prim_buffer; + drm_device_dma_t *dma = dev->dma; + int next_prim_idx; + int ret = 0; + + /* This needs to reset the primary buffer if available, + * we should collect stats on how many times it bites + * it's tail */ + DRM_DEBUG("%s\n", __FUNCTION__); + + next_prim_idx = dev_priv->current_prim_idx + 1; + if(next_prim_idx >= MGA_NUM_PRIM_BUFS) + next_prim_idx = 0; + prim_buffer = dev_priv->prim_bufs[next_prim_idx]; + set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + + /* In use is cleared in interrupt handler */ + + if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) { + add_wait_queue(&dev_priv->wait_queue, &entry); + current->state = TASK_INTERRUPTIBLE; + + for (;;) { + mga_dma_schedule(dev, 0); + if(!test_and_set_bit(MGA_BUF_IN_USE, + &prim_buffer->buffer_status)) + break; + atomic_inc(&dev->total_sleeps); + atomic_inc(&dma->total_missed_sched); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->wait_queue, &entry); + if(ret) return ret; + } + clear_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + + /* This primary buffer is now free to use */ + prim_buffer->current_dma_ptr = prim_buffer->head; + prim_buffer->num_dwords = 0; + prim_buffer->sec_used = 0; + prim_buffer->prim_age = dev_priv->next_prim_age++; + if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + mga_reset_freelist(dev); + prim_buffer->prim_age = (dev_priv->next_prim_age += 2); + } - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; + /* Reset all buffer status stuff */ + clear_bit(MGA_BUF_NEEDS_OVERFLOW, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_FORCE_FIRE, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_SWAP_PENDING, &prim_buffer->buffer_status); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + dev_priv->current_prim = prim_buffer; + dev_priv->current_prim_idx = next_prim_idx; + return 0; } -/* Frees dispatch lock */ -static inline void mga_dma_quiescent(drm_device_t *dev) +/* More dynamic performance decisions */ +static inline int mga_decide_to_fire(drm_device_t *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; - while(1) { - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - break; - } else { - atomic_dec(&dev_priv->dispatch_lock); - } - } - while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) ; -#if 0 - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); -#endif - while(MGA_READ(MGAREG_DWGSYNC) == MGA_SYNC_TAG) ; - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - atomic_dec(&dev_priv->dispatch_lock); -} + DRM_DEBUG("%s\n", __FUNCTION__); -/* Keeps dispatch lock held */ + if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) { + atomic_inc(&dma->total_prio); + return 1; + } -static inline int mga_dma_is_ready(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock */ - return 1; - } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; + if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + atomic_inc(&dma->total_prio); + return 1; } -} -static inline int mga_dma_is_ready_no_hold(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + atomic_inc(&dma->total_prio); + return 1; + } - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock, but free it */ - atomic_dec(&dev_priv->dispatch_lock); - return 1; - } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { + if(test_bit(MGA_BUF_SWAP_PENDING, + &dev_priv->next_prim->buffer_status)) { + atomic_inc(&dma->total_dmas); + return 1; + } } -} -static void mga_dma_service(int irq, void *device, struct pt_regs *regs) -{ - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - atomic_dec(&dev_priv->dispatch_lock); - atomic_inc(&dev->total_irq); - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); - - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; - } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) { + atomic_inc(&dma->total_hit); + return 1; + } } - clear_bit(0, &dev->dma_flag); - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) { + atomic_inc(&dma->total_missed_free); + return 1; + } + } + atomic_inc(&dma->total_tried); + return 0; } -/* Only called by mga_dma_schedule. */ -static int mga_do_dma(drm_device_t *dev, int locked) +int mga_dma_schedule(drm_device_t *dev, int locked) { - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_buf_priv_t *buf_priv; + drm_device_dma_t *dma = dev->dma; - printk("mga_do_dma\n"); - if (test_and_set_bit(0, &dev->dma_flag)) { + if (test_and_set_bit(0, &dev->dma_flag)) { atomic_inc(&dma->total_missed_dma); return -EBUSY; } - - if (!dma->next_buffer) { - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - buf = dma->next_buffer; - - printk("context %d, buffer %d\n", buf->context, buf->idx); - - if (buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } + + DRM_DEBUG("%s\n", __FUNCTION__); - if (!buf->used) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (mga_dma_is_ready(dev) == 0) { - clear_bit(0, &dev->dma_flag); - return -EBUSY; + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || + test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) || + test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { + locked = 1; } - /* Always hold the hardware lock while dispatching. - */ - if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - atomic_dec(&dev_priv->dispatch_lock); - return -EBUSY; + if (!locked && + !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { + atomic_inc(&dma->total_missed_lock); + clear_bit(0, &dev->dma_flag); + DRM_DEBUG("Not locked\n"); + return -EBUSY; } - - dma->next_queue = dev->queuelist[DRM_KERNEL_CONTEXT]; - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; - - buf_priv = buf->dev_private; - - printk("dispatch!\n"); - switch (buf_priv->dma_type) { - case MGA_DMA_GENERAL: - mga_dma_dispatch_general(dev, buf); - break; - case MGA_DMA_VERTEX: - mga_dma_dispatch_vertex(dev, buf); - break; -/* case MGA_DMA_SETUP: */ -/* mga_dma_dispatch_setup(dev, address, length); */ -/* break; */ - case MGA_DMA_ILOAD: - mga_dma_dispatch_iload(dev, buf); - break; - default: - printk("bad buffer type %x in dispatch\n", buf_priv->dma_type); - break; + DRM_DEBUG("I'm locked\n"); + + if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { + /* Fire dma buffer */ + if(mga_decide_to_fire(dev)) { + DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); + clear_bit(MGA_BUF_FORCE_FIRE, + &dev_priv->next_prim->buffer_status); + if(dev_priv->current_prim == dev_priv->next_prim) { + /* Schedule overflow for a later time */ + set_bit(MGA_BUF_NEEDS_OVERFLOW, + &dev_priv->next_prim->buffer_status); + } + mga_fire_primary(dev, dev_priv->next_prim); + } else { + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); + } + } else { + DRM_DEBUG("I can't get the dispatch lock\n"); } - atomic_dec(&dev_priv->pending_bufs); - - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = buf; - - atomic_add(buf->used, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - + if (!locked) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { @@ -692,90 +622,242 @@ static int mga_do_dma(drm_device_t *dev, int locked) } } - clear_bit(0, &dev->dma_flag); - - if(!atomic_read(&dev_priv->pending_bufs)) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - -#if 0 - wake_up_interruptible(&dev->lock.lock_queue); -#endif - - /* We hold the dispatch lock until the interrupt handler - * frees it - */ - return retcode; + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords == 0 && + atomic_read(&dev_priv->pending_bufs) == 0) { + /* Everything has been processed by the hardware */ + clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); + wake_up_interruptible(&dev_priv->flush_queue); + } + + if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->tail->age < dev_priv->last_prim_age) { + clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + DRM_DEBUG("Waking up buf queue\n"); + wake_up_interruptible(&dev_priv->buf_queue); + } else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { + DRM_DEBUG("Not waking buf_queue on %d %d\n", + atomic_read(&dev->total_irq), + dev_priv->last_prim_age); + } + + clear_bit(0, &dev->dma_flag); + return 0; } -static void mga_dma_schedule_timer_wrapper(unsigned long dev) +static void mga_dma_service(int irq, void *device, struct pt_regs *regs) { - mga_dma_schedule((drm_device_t *)dev, 0); + drm_device_t *dev = (drm_device_t *)device; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_prim_buf_t *last_prim_buffer; + + DRM_DEBUG("%s\n", __FUNCTION__); + atomic_inc(&dev->total_irq); + if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + last_prim_buffer = dev_priv->last_prim; + last_prim_buffer->num_dwords = 0; + last_prim_buffer->sec_used = 0; + dev_priv->sarea_priv->last_dispatch = + dev_priv->last_prim_age = last_prim_buffer->prim_age; + clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status); + wake_up_interruptible(&dev_priv->wait_queue); + clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); + atomic_dec(&dev_priv->pending_bufs); + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); } -static void mga_dma_schedule_tq_wrapper(void *dev) +static void mga_dma_task_queue(void *device) { - mga_dma_schedule(dev, 0); + DRM_DEBUG("%s\n", __FUNCTION__); + mga_dma_schedule((drm_device_t *)device, 0); } -int mga_dma_schedule(drm_device_t *dev, int locked) +int mga_dma_cleanup(drm_device_t *dev) { - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; - - printk("mga_dma_schedule\n"); - - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; - } - missed = atomic_read(&dma->total_missed_sched); + DRM_DEBUG("%s\n", __FUNCTION__); -again: - /* There is only one queue: - */ - if (!dma->next_buffer && DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { - q = dev->queuelist[DRM_KERNEL_CONTEXT]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); + if(dev->dev_private) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + + if(dev_priv->ioremap) { + int temp = (dev_priv->warp_ucode_size + + dev_priv->primary_size + + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + + drm_ioremapfree((void *) dev_priv->ioremap, temp); + } + if(dev_priv->status_page != NULL) { + iounmap(dev_priv->status_page); + } + if(dev_priv->real_status_page != 0UL) { + mga_free_page(dev, dev_priv->real_status_page); + } + if(dev_priv->prim_bufs != NULL) { + int i; + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + if(dev_priv->prim_bufs[i] != NULL) { + drm_free(dev_priv->prim_bufs[i], + sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + } + } + drm_free(dev_priv->prim_bufs, sizeof(void *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + } + if(dev_priv->head != NULL) { + mga_freelist_cleanup(dev); } + + + drm_free(dev->dev_private, sizeof(drm_mga_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; } - if (dma->next_buffer) { - if (!(retcode = mga_do_dma(dev, locked))) - ++processed; + return 0; +} + +static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { + drm_mga_private_t *dev_priv; + drm_map_t *sarea_map = NULL; + int i; + + DRM_DEBUG("%s\n", __FUNCTION__); + + dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *) dev_priv; + + memset(dev_priv, 0, sizeof(drm_mga_private_t)); + + if((init->reserved_map_idx >= dev->map_count) || + (init->buffer_map_idx >= dev->map_count)) { + mga_dma_cleanup(dev); + DRM_DEBUG("reserved_map or buffer_map are invalid\n"); + return -EINVAL; } + + dev_priv->reserved_map_idx = init->reserved_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_mga_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); - /* Try again if we succesfully dispatched a buffer, or if someone - * tried to schedule while we were working. - */ - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (mga_dma_is_ready_no_hold(dev)) - goto again; - } + /* Scale primary size to the next page */ + dev_priv->chipset = init->chipset; + dev_priv->frontOffset = init->frontOffset; + dev_priv->backOffset = init->backOffset; + dev_priv->depthOffset = init->depthOffset; + dev_priv->textureOffset = init->textureOffset; + dev_priv->textureSize = init->textureSize; + dev_priv->cpp = init->cpp; + dev_priv->sgram = init->sgram; + dev_priv->stride = init->stride; - if (processed && mga_dma_is_ready_no_hold(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } + dev_priv->mAccess = init->mAccess; + init_waitqueue_head(&dev_priv->flush_queue); + init_waitqueue_head(&dev_priv->buf_queue); + dev_priv->WarpPipe = -1; + + DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", + dev_priv->chipset, dev_priv->warp_ucode_size, + dev_priv->backOffset, dev_priv->depthOffset); + DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", + dev_priv->cpp, dev_priv->sgram, dev_priv->stride, + dev_priv->mAccess); + + memcpy(&dev_priv->WarpIndex, &init->WarpIndex, + sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES); + + for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) + DRM_DEBUG("warp pipe %d: installed: %d phys: %lx size: %x\n", + i, + dev_priv->WarpIndex[i].installed, + dev_priv->WarpIndex[i].phys_addr, + dev_priv->WarpIndex[i].size); + + if(mga_init_primary_bufs(dev, init) != 0) { + DRM_ERROR("Can not initialize primary buffers\n"); + mga_dma_cleanup(dev); + return -ENOMEM; } - - clear_bit(0, &dev->interrupt_flag); - - return retcode; + dev_priv->real_status_page = mga_alloc_page(dev); + if(dev_priv->real_status_page == 0UL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not allocate status page\n"); + return -ENOMEM; + } + + dev_priv->status_page = + ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), + PAGE_SIZE); + + if(dev_priv->status_page == NULL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not remap status page\n"); + return -ENOMEM; + } + + /* Write status page when secend or softrap occurs */ + MGA_WRITE(MGAREG_PRIMPTR, + virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); + + + /* Private is now filled in, initialize the hardware */ + { + PRIMLOCALS; + PRIMGETPTR( dev_priv ); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0x0100); + PRIMOUTREG(MGAREG_SOFTRAP, 0); + /* Poll for the first buffer to insure that + * the status register will be correct + */ + + mga_flush_write_combine(); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + + MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | + PDEA_pagpxfer_enable)); + + while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ; + } + + if(mga_freelist_init(dev) != 0) { + DRM_ERROR("Could not initialize freelist\n"); + mga_dma_cleanup(dev); + return -ENOMEM; + } + return 0; +} + +int mga_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mga_init_t init; + + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + + switch(init.func) { + case MGA_INIT_DMA: + return mga_dma_initialize(dev, &init); + case MGA_CLEANUP_DMA: + return mga_dma_cleanup(dev); + } + + return -EINVAL; } int mga_irq_install(drm_device_t *dev, int irq) @@ -792,7 +874,7 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); - printk("install irq handler %d\n", irq); + DRM_DEBUG("install irq handler %d\n", irq); dev->context_flag = 0; dev->interrupt_flag = 0; @@ -802,17 +884,15 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->dma->this_buffer = NULL; dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = mga_dma_schedule_tq_wrapper; + dev->tq.routine = mga_dma_task_queue; dev->tq.data = dev; /* Before installing handler */ - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); MGA_WRITE(MGAREG_IEN, 0); - /* Install handler */ if ((retcode = request_irq(dev->irq, mga_dma_service, - 0, + SA_SHIRQ, dev->devname, dev))) { down(&dev->struct_sem); @@ -820,11 +900,9 @@ int mga_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - /* After installing handler */ - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0x00000001); - return 0; } @@ -838,19 +916,13 @@ int mga_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - - printk("remove irq handler %d\n", irq); - - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); + DRM_DEBUG("remove irq handler %d\n", irq); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0); - MGA_WRITE(MGAREG_ICLEAR, 0xfa7); - free_irq(irq, dev); - return 0; } - int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -859,7 +931,9 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); - + + DRM_DEBUG("%s\n", __FUNCTION__); + switch (ctl.func) { case DRM_INST_HANDLER: return mga_irq_install(dev, ctl.irq); @@ -870,36 +944,69 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, } } -int mga_flush_queue(drm_device_t *dev) +static int mga_flush_queue(drm_device_t *dev) { DECLARE_WAITQUEUE(entry, current); - drm_queue_t *q = dev->queuelist[DRM_KERNEL_CONTEXT]; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; - - printk("mga_flush_queue\n"); - if(atomic_read(&dev_priv->pending_bufs) != 0) { - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&q->flush_queue, &entry); - for (;;) { - if (!atomic_read(&dev_priv->pending_bufs)) break; - printk("Calling schedule from flush_queue : %d\n", - atomic_read(&dev_priv->pending_bufs)); - mga_dma_schedule(dev, 1); - schedule(); - if (signal_pending(current)) { - ret = -EINTR; /* Can't restart */ - break; - } - } - printk("Exited out of schedule from flush_queue\n"); - current->state = TASK_RUNNING; - remove_wait_queue(&q->flush_queue, &entry); + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(dev_priv == NULL) { + return 0; } + if(dev_priv->next_prim->num_dwords != 0) { + set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + for (;;) { + mga_dma_schedule(dev, 0); + if (!test_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status)) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + clear_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status); + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + } return ret; } +/* Must be called with the lock held */ +void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if(dev->dev_private == NULL) return; + if(dma->buflist == NULL) return; + + DRM_DEBUG("%s\n", __FUNCTION__); + mga_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + /* Only buffers that need to get reclaimed ever + * get set to free + */ + if (buf->pid == pid && buf_priv) { + if(buf_priv->my_freelist->age == MGA_BUF_USED) + buf_priv->my_freelist->age = MGA_BUF_FREE; + } + } +} + int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -909,6 +1016,7 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, int ret = 0; drm_lock_t lock; + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); if (lock.context == DRM_KERNEL_CONTEXT) { @@ -916,16 +1024,15 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, current->pid, lock.context); return -EINVAL; } - - printk("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock.context, current->pid, dev->lock.hw_lock->lock, - lock.flags); - + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); if (lock.context < 0) { return -EINVAL; } - + /* Only one queue: */ @@ -948,8 +1055,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; - printk("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -962,17 +1067,46 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, if (!ret) { if (lock.flags & _DRM_LOCK_QUIESCENT) { - printk("_DRM_LOCK_QUIESCENT\n"); - ret = mga_flush_queue(dev); - if(ret != 0) { - drm_lock_free(dev, &dev->lock.hw_lock->lock, - lock.context); - } else { - mga_dma_quiescent(dev); - } + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + mga_flush_queue(dev); + mga_dma_quiescent(dev); } } - printk("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); return ret; } +int mga_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) { + drm_mga_prim_buf_t *temp_buf = + dev_priv->prim_bufs[dev_priv->current_prim_idx]; + + if(temp_buf && temp_buf->num_dwords) { + set_bit(MGA_BUF_FORCE_FIRE, &temp_buf->buffer_status); + mga_advance_primary(dev); + mga_dma_schedule(dev, 1); + } + } + if(lock.flags & _DRM_LOCK_QUIESCENT) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + } + + return 0; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drm.h new file mode 100644 index 000000000..7228b9051 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drm.h @@ -0,0 +1,269 @@ +/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Tue Jan 25 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Jeff Hartmann <jhartmann@precisioninsight.com> + * Keith Whitwell <keithw@precisioninsight.com> + * + * $XFree86$ + */ + +#ifndef _MGA_DRM_H_ +#define _MGA_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmMga.h) + */ +#ifndef _MGA_DEFINES_ +#define _MGA_DEFINES_ + +#define MGA_F 0x1 /* fog */ +#define MGA_A 0x2 /* alpha */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + +#define MGA_WARP_TGZ 0 +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZAF (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) + +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_G200_PIPES 8 /* no multitex */ +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES + +#define MGA_CARD_TYPE_G200 1 +#define MGA_CARD_TYPE_G400 2 + +#define MGA_FRONT 0x1 +#define MGA_BACK 0x2 +#define MGA_DEPTH 0x4 + +/* 3d state excluding texture units: + */ +#define MGA_CTXREG_DSTORG 0 /* validated */ +#define MGA_CTXREG_MACCESS 1 +#define MGA_CTXREG_PLNWT 2 +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTXREG_FCOL 9 +#define MGA_CTX_SETUP_SIZE 10 + +/* 2d state + */ +#define MGA_2DREG_PITCH 0 +#define MGA_2D_SETUP_SIZE 1 + +/* Each texture unit has a state: + */ +#define MGA_TEXREG_CTL 0 +#define MGA_TEXREG_CTL2 1 +#define MGA_TEXREG_FILTER 2 +#define MGA_TEXREG_BORDERCOL 3 +#define MGA_TEXREG_ORG 4 /* validated */ +#define MGA_TEXREG_ORG1 5 +#define MGA_TEXREG_ORG2 6 +#define MGA_TEXREG_ORG3 7 +#define MGA_TEXREG_ORG4 8 +#define MGA_TEXREG_WIDTH 9 +#define MGA_TEXREG_HEIGHT 10 +#define MGA_TEX_SETUP_SIZE 11 + +/* What needs to be changed for the current vertex dma buffer? + */ +#define MGA_UPLOAD_CTX 0x1 +#define MGA_UPLOAD_TEX0 0x2 +#define MGA_UPLOAD_TEX1 0x4 +#define MGA_UPLOAD_PIPE 0x8 +#define MGA_UPLOAD_TEX0IMAGE 0x10 /* handled client-side */ +#define MGA_UPLOAD_TEX1IMAGE 0x20 /* handled client-side */ +#define MGA_UPLOAD_2D 0x40 +#define MGA_WAIT_AGE 0x80 /* handled client-side */ +#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ +#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock + quiescent */ + +/* 32 buffers of 64k each, total 2 meg. + */ +#define MGA_DMA_BUF_ORDER 16 +#define MGA_DMA_BUF_SZ (1<<MGA_DMA_BUF_ORDER) +#define MGA_DMA_BUF_NR 31 + +/* Keep these small for testing. + */ +#define MGA_NR_SAREA_CLIPRECTS 8 + +/* 2 heaps (1 for card, 1 for agp), each divided into upto 128 + * regions, subject to a minimum region size of (1<<16) == 64k. + * + * Clients may subdivide regions internally, but when sharing between + * clients, the region size is the minimum granularity. + */ + +#define MGA_CARD_HEAP 0 +#define MGA_AGP_HEAP 1 +#define MGA_NR_TEX_HEAPS 2 +#define MGA_NR_TEX_REGIONS 16 +#define MGA_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +typedef struct _drm_mga_warp_index { + int installed; + unsigned long phys_addr; + int size; +} drm_mga_warp_index_t; + +typedef struct drm_mga_init { + enum { + MGA_INIT_DMA = 0x01, + MGA_CLEANUP_DMA = 0x02 + } func; + int reserved_map_agpstart; + int reserved_map_idx; + int buffer_map_idx; + int sarea_priv_offset; + int primary_size; + int warp_ucode_size; + unsigned int frontOffset; + unsigned int backOffset; + unsigned int depthOffset; + unsigned int textureOffset; + unsigned int textureSize; + unsigned int agpTextureOffset; + unsigned int agpTextureSize; + unsigned int cpp; + unsigned int stride; + int sgram; + int chipset; + drm_mga_warp_index_t WarpIndex[MGA_MAX_WARP_PIPES]; + unsigned int mAccess; +} drm_mga_init_t; + +/* Warning: if you change the sarea structure, you must change the Xserver + * structures as well */ + +typedef struct _drm_mga_tex_region { + unsigned char next, prev; + unsigned char in_use; + unsigned int age; +} drm_mga_tex_region_t; + +typedef struct _drm_mga_sarea { + /* The channel for communication of state information to the kernel + * on firing a vertex dma buffer. + */ + unsigned int ContextState[MGA_CTX_SETUP_SIZE]; + unsigned int ServerState[MGA_2D_SETUP_SIZE]; + unsigned int TexState[2][MGA_TEX_SETUP_SIZE]; + unsigned int WarpPipe; + unsigned int dirty; + + unsigned int nbox; + drm_clip_rect_t boxes[MGA_NR_SAREA_CLIPRECTS]; + + + /* Information about the most recently used 3d drawable. The + * client fills in the req_* fields, the server fills in the + * exported_ fields and puts the cliprects into boxes, above. + * + * The client clears the exported_drawable field before + * clobbering the boxes data. + */ + unsigned int req_drawable; /* the X drawable id */ + unsigned int req_draw_buffer; /* MGA_FRONT or MGA_BACK */ + + unsigned int exported_drawable; + unsigned int exported_index; + unsigned int exported_stamp; + unsigned int exported_buffers; + unsigned int exported_nfront; + unsigned int exported_nback; + int exported_back_x, exported_front_x, exported_w; + int exported_back_y, exported_front_y, exported_h; + drm_clip_rect_t exported_boxes[MGA_NR_SAREA_CLIPRECTS]; + + /* Counters for aging textures and for client-side throttling. + */ + unsigned int last_enqueue; /* last time a buffer was enqueued */ + unsigned int last_dispatch; /* age of the most recently dispatched buffer */ + unsigned int last_quiescent; /* */ + + + /* LRU lists for texture memory in agp space and on the card + */ + drm_mga_tex_region_t texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS+1]; + unsigned int texAge[MGA_NR_TEX_HEAPS]; + + /* Mechanism to validate card state. + */ + int ctxOwner; +} drm_mga_sarea_t; + +/* Device specific ioctls: + */ +typedef struct _drm_mga_clear { + unsigned int clear_color; + unsigned int clear_depth; + unsigned int flags; +} drm_mga_clear_t; + +typedef struct _drm_mga_swap { + int dummy; +} drm_mga_swap_t; + +typedef struct _drm_mga_iload { + int idx; + int length; + unsigned int destOrg; +} drm_mga_iload_t; + +typedef struct _drm_mga_vertex { + int idx; /* buffer to queue */ + int used; /* bytes in use */ + int discard; /* client finished with buffer? */ +} drm_mga_vertex_t; + +typedef struct _drm_mga_indices { + int idx; /* buffer to queue */ + unsigned int start; + unsigned int end; + int discard; /* client finished with buffer? */ +} drm_mga_indices_t; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.c index 8bc25617e..5fabe1f25 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.c @@ -54,6 +54,7 @@ static struct file_operations mga_fops = { mmap: drm_mmap, read: drm_read, fasync: drm_fasync, + poll: drm_poll, }; static struct miscdevice mga_misc = { @@ -105,9 +106,12 @@ static drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_clear_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_swap_bufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0 }, }; #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -380,6 +384,21 @@ int mga_init(void) drm_proc_init(dev); DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); + if(dev->agp == NULL) { + DRM_DEBUG("The mga drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the mga module\n"); + drm_proc_cleanup(); + misc_deregister(&mga_misc); + mga_takedown(dev); + return -ENOMEM; + } +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024 * 1024, + MTRR_TYPE_WRCOMB, + 1); +#endif DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -416,6 +435,16 @@ void mga_cleanup(void) } drm_ctxbitmap_cleanup(dev); mga_dma_cleanup(dev); +#ifdef CONFIG_MTRR + if(dev->agp && dev->agp->agp_mtrr) { + int retval; + retval = mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024*1024); + DRM_DEBUG("mtrr_del = %d\n", retval); + } +#endif + mga_takedown(dev); if (dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -482,27 +511,86 @@ int mga_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + mga_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return mga_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + mga_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return mga_takedown(dev); + } + spin_unlock(&dev->count_lock); return retcode; } + /* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h index bc7808b0a..ee75a03e2 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h @@ -26,48 +26,79 @@ * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com> * Jeff Hartmann <jhartmann@precisioninsight.com> * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_drv.h,v 1.1 2000/02/11 17:26:08 dawes Exp $ + * $XFree86$ */ #ifndef _MGA_DRV_H_ #define _MGA_DRV_H_ -#include "mga_drm_public.h" + +#define MGA_BUF_IN_USE 0 +#define MGA_BUF_SWAP_PENDING 1 +#define MGA_BUF_FORCE_FIRE 2 +#define MGA_BUF_NEEDS_OVERFLOW 3 + +typedef struct { + u32 buffer_status; + unsigned int num_dwords; + unsigned int max_dwords; + u32 *current_dma_ptr; + u32 *head; + u32 phys_head; + unsigned int prim_age; + int sec_used; + int idx; +} drm_mga_prim_buf_t; + +typedef struct _drm_mga_freelist { + unsigned int age; + drm_buf_t *buf; + struct _drm_mga_freelist *next; + struct _drm_mga_freelist *prev; +} drm_mga_freelist_t; + +#define MGA_IN_DISPATCH 0 +#define MGA_IN_FLUSH 1 +#define MGA_IN_WAIT 2 +#define MGA_IN_GETBUF 3 typedef struct _drm_mga_private { + u32 dispatch_status; + unsigned int next_prim_age; + __volatile__ unsigned int last_prim_age; int reserved_map_idx; int buffer_map_idx; drm_mga_sarea_t *sarea_priv; int primary_size; int warp_ucode_size; int chipset; - int fbOffset; - int backOffset; - int depthOffset; - int textureOffset; - int textureSize; + unsigned int frontOffset; + unsigned int backOffset; + unsigned int depthOffset; + unsigned int textureOffset; + unsigned int textureSize; int cpp; - int stride; + unsigned int stride; int sgram; int use_agp; - mgaWarpIndex WarpIndex[MGA_MAX_G400_PIPES]; - __volatile__ unsigned long softrap_age; - atomic_t dispatch_lock; + drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES]; + unsigned int WarpPipe; atomic_t pending_bufs; - void *ioremap; - u32 *prim_head; - u32 *current_dma_ptr; - u32 prim_phys_head; - int prim_num_dwords; - int prim_max_dwords; - - + void *status_page; + unsigned long real_status_page; + u8 *ioremap; + drm_mga_prim_buf_t **prim_bufs; + drm_mga_prim_buf_t *next_prim; + drm_mga_prim_buf_t *last_prim; + drm_mga_prim_buf_t *current_prim; + int current_prim_idx; + drm_mga_freelist_t *head; + drm_mga_freelist_t *tail; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + wait_queue_head_t wait_queue; /* Processes waiting until interrupt */ + wait_queue_head_t buf_queue; /* Processes waiting for a free buf */ /* Some validated register values: */ - u32 frontOrg; - u32 backOrg; - u32 depthOrg; u32 mAccess; - } drm_mga_private_t; /* mga_drv.c */ @@ -92,16 +123,19 @@ extern int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -#if 0 -extern void mga_dma_init(drm_device_t *dev); -extern void mga_dma_cleanup(drm_device_t *dev); -#endif +/* mga_dma_init does init and release */ extern int mga_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_dma_cleanup(drm_device_t *dev); - -/* mga_dma_init does init and release */ +extern int mga_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void mga_flush_write_combine(void); +extern unsigned int mga_create_sync_tag(drm_device_t *dev); +extern drm_buf_t *mga_freelist_get(drm_device_t *dev); +extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); +extern int mga_advance_primary(drm_device_t *dev); +extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid); /* mga_bufs.c */ @@ -124,6 +158,10 @@ extern int mga_swap_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_iload(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int mga_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_indices(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* mga_context.c */ extern int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -144,13 +182,124 @@ extern int mga_context_switch(drm_device_t *dev, int old, int new); extern int mga_context_switch_complete(drm_device_t *dev, int new); +typedef enum { + TT_GENERAL, + TT_BLIT, + TT_VECTOR, + TT_VERTEX +} transferType_t; + +typedef struct { + drm_mga_freelist_t *my_freelist; + int discard; + int dispatched; +} drm_mga_buf_priv_t; + +#define DWGREG0 0x1c00 +#define DWGREG0_END 0x1dff +#define DWGREG1 0x2c00 +#define DWGREG1_END 0x2dff + +#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) +#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) +#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) +#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) + +#define MGA_VERBOSE 0 +#define MGA_NUM_PRIM_BUFS 8 + +#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ + int outcount, num_dwords + +#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \ + &tmp_buf->buffer_status)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length ||\ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } \ +} while(0) + +#define PRIMGETPTR(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \ + dma_ptr = tmp_buf->current_dma_ptr; \ + num_dwords = tmp_buf->num_dwords; \ + phys_head = tmp_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMPTR(prim_buf) do { \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMPTR in %s\n", __FUNCTION__); \ + dma_ptr = prim_buf->current_dma_ptr; \ + num_dwords = prim_buf->num_dwords; \ + phys_head = prim_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMFINISH(prim_buf) do { \ + if (MGA_VERBOSE) { \ + DRM_DEBUG( "PRIMFINISH in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + prim_buf->num_dwords = num_dwords; \ + prim_buf->current_dma_ptr = dma_ptr; \ +} while(0) + +#define PRIMADVANCE(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if (MGA_VERBOSE) { \ + DRM_DEBUG("PRIMADVANCE in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + tmp_buf->num_dwords = num_dwords; \ + tmp_buf->current_dma_ptr = dma_ptr; \ +} while (0) + +#define PRIMUPDATE(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + tmp_buf->sec_used++; \ +} while (0) + +#define AGEBUF(dev_priv, buf_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + buf_priv->my_freelist->age = tmp_buf->prim_age; \ +} while (0) + + +#define PRIMOUTREG(reg, val) do { \ + tempIndex[outcount]=ADRINDEX(reg); \ + dma_ptr[1+outcount] = val; \ + if (MGA_VERBOSE) \ + DRM_DEBUG(" PRIMOUT %d: 0x%x -- 0x%x\n", \ + num_dwords + 1 + outcount, ADRINDEX(reg), val); \ + if( ++outcount == 4) { \ + outcount = 0; \ + dma_ptr[0] = *(u32 *)tempIndex; \ + dma_ptr+=5; \ + num_dwords += 5; \ + } \ +}while (0) + +/* A reduced set of the mga registers. + */ #define MGAREG_MGA_EXEC 0x0100 -#define MGAREG_AGP_PLL 0x1e4c #define MGAREG_ALPHACTRL 0x2c7c -#define MGAREG_ALPHASTART 0x2c70 -#define MGAREG_ALPHAXINC 0x2c74 -#define MGAREG_ALPHAYINC 0x2c78 #define MGAREG_AR0 0x1c60 #define MGAREG_AR1 0x1c64 #define MGAREG_AR2 0x1c68 @@ -158,39 +307,16 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_AR4 0x1c70 #define MGAREG_AR5 0x1c74 #define MGAREG_AR6 0x1c78 -#define MGAREG_BCOL 0x1c20 #define MGAREG_CXBNDRY 0x1c80 #define MGAREG_CXLEFT 0x1ca0 #define MGAREG_CXRIGHT 0x1ca4 #define MGAREG_DMAPAD 0x1c54 -#define MGAREG_DR0_Z32LSB 0x2c50 -#define MGAREG_DR0_Z32MSB 0x2c54 -#define MGAREG_DR2_Z32LSB 0x2c60 -#define MGAREG_DR2_Z32MSB 0x2c64 -#define MGAREG_DR3_Z32LSB 0x2c68 -#define MGAREG_DR3_Z32MSB 0x2c6c -#define MGAREG_DR0 0x1cc0 -#define MGAREG_DR2 0x1cc8 -#define MGAREG_DR3 0x1ccc -#define MGAREG_DR4 0x1cd0 -#define MGAREG_DR6 0x1cd8 -#define MGAREG_DR7 0x1cdc -#define MGAREG_DR8 0x1ce0 -#define MGAREG_DR10 0x1ce8 -#define MGAREG_DR11 0x1cec -#define MGAREG_DR12 0x1cf0 -#define MGAREG_DR14 0x1cf8 -#define MGAREG_DR15 0x1cfc #define MGAREG_DSTORG 0x2cb8 -#define MGAREG_DWG_INDIR_WT 0x1e80 #define MGAREG_DWGCTL 0x1c00 #define MGAREG_DWGSYNC 0x2c4c #define MGAREG_FCOL 0x1c24 #define MGAREG_FIFOSTATUS 0x1e10 #define MGAREG_FOGCOL 0x1cf4 -#define MGAREG_FOGSTART 0x1cc4 -#define MGAREG_FOGXINC 0x1cd4 -#define MGAREG_FOGYINC 0x1ce4 #define MGAREG_FXBNDRY 0x1c84 #define MGAREG_FXLEFT 0x1ca8 #define MGAREG_FXRIGHT 0x1cac @@ -198,44 +324,22 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_IEN 0x1e1c #define MGAREG_LEN 0x1c5c #define MGAREG_MACCESS 0x1c04 -#define MGAREG_MCTLWTST 0x1c08 -#define MGAREG_MEMRDBK 0x1e44 -#define MGAREG_OPMODE 0x1e54 -#define MGAREG_PAT0 0x1c10 -#define MGAREG_PAT1 0x1c14 #define MGAREG_PITCH 0x1c8c #define MGAREG_PLNWT 0x1c1c #define MGAREG_PRIMADDRESS 0x1e58 #define MGAREG_PRIMEND 0x1e5c #define MGAREG_PRIMPTR 0x1e50 -#define MGAREG_RST 0x1e40 #define MGAREG_SECADDRESS 0x2c40 #define MGAREG_SECEND 0x2c44 #define MGAREG_SETUPADDRESS 0x2cd0 #define MGAREG_SETUPEND 0x2cd4 -#define MGAREG_SGN 0x1c58 -#define MGAREG_SHIFT 0x1c50 #define MGAREG_SOFTRAP 0x2c48 -#define MGAREG_SPECBSTART 0x2c98 -#define MGAREG_SPECBXINC 0x2c9c -#define MGAREG_SPECBYINC 0x2ca0 -#define MGAREG_SPECGSTART 0x2c8c -#define MGAREG_SPECGXINC 0x2c90 -#define MGAREG_SPECGYINC 0x2c94 -#define MGAREG_SPECRSTART 0x2c80 -#define MGAREG_SPECRXINC 0x2c84 -#define MGAREG_SPECRYINC 0x2c88 -#define MGAREG_SRC0 0x1c30 -#define MGAREG_SRC1 0x1c34 -#define MGAREG_SRC2 0x1c38 -#define MGAREG_SRC3 0x1c3c #define MGAREG_SRCORG 0x2cb4 #define MGAREG_STATUS 0x1e14 #define MGAREG_STENCIL 0x2cc8 #define MGAREG_STENCILCTL 0x2ccc #define MGAREG_TDUALSTAGE0 0x2cf8 #define MGAREG_TDUALSTAGE1 0x2cfc -#define MGAREG_TEST0 0x1e48 #define MGAREG_TEXBORDERCOL 0x2c5c #define MGAREG_TEXCTL 0x2c30 #define MGAREG_TEXCTL2 0x2c3c @@ -249,18 +353,6 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_TEXTRANS 0x2c34 #define MGAREG_TEXTRANSHIGH 0x2c38 #define MGAREG_TEXWIDTH 0x2c28 -#define MGAREG_TMR0 0x2c00 -#define MGAREG_TMR1 0x2c04 -#define MGAREG_TMR2 0x2c08 -#define MGAREG_TMR3 0x2c0c -#define MGAREG_TMR4 0x2c10 -#define MGAREG_TMR5 0x2c14 -#define MGAREG_TMR6 0x2c18 -#define MGAREG_TMR7 0x2c1c -#define MGAREG_TMR8 0x2c20 -#define MGAREG_VBIADDR0 0x3e08 -#define MGAREG_VBIADDR1 0x3e0c -#define MGAREG_VCOUNT 0x1e20 #define MGAREG_WACCEPTSEQ 0x1dd4 #define MGAREG_WCODEADDR 0x1e6c #define MGAREG_WFLAG 0x1dc4 @@ -270,18 +362,8 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_WGETMSB 0x1dc8 #define MGAREG_WIADDR 0x1dc0 #define MGAREG_WIADDR2 0x1dd8 -#define MGAREG_WIADDRNB 0x1e60 -#define MGAREG_WIADDRNB1 0x1e04 -#define MGAREG_WIADDRNB2 0x1e00 -#define MGAREG_WIMEMADDR 0x1e68 -#define MGAREG_WIMEMDATA 0x2000 -#define MGAREG_WIMEMDATA1 0x2100 #define MGAREG_WMISC 0x1e70 -#define MGAREG_WR 0x2d00 #define MGAREG_WVRTXSZ 0x1dcc -#define MGAREG_XDST 0x1cb0 -#define MGAREG_XYEND 0x1c44 -#define MGAREG_XYSTRT 0x1c40 #define MGAREG_YBOT 0x1c9c #define MGAREG_YDST 0x1c90 #define MGAREG_YDSTLEN 0x1c88 @@ -289,4 +371,77 @@ extern int mga_context_switch_complete(drm_device_t *dev, int new); #define MGAREG_YTOP 0x1c98 #define MGAREG_ZORG 0x1c0c +#define PDEA_pagpxfer_enable 0x2 + +#define WIA_wmode_suspend 0x0 +#define WIA_wmode_start 0x3 +#define WIA_wagp_agp 0x4 + +#define DC_opcod_line_open 0x0 +#define DC_opcod_autoline_open 0x1 +#define DC_opcod_line_close 0x2 +#define DC_opcod_autoline_close 0x3 +#define DC_opcod_trap 0x4 +#define DC_opcod_texture_trap 0x6 +#define DC_opcod_bitblt 0x8 +#define DC_opcod_iload 0x9 +#define DC_atype_rpl 0x0 +#define DC_atype_rstr 0x10 +#define DC_atype_zi 0x30 +#define DC_atype_blk 0x40 +#define DC_atype_i 0x70 +#define DC_linear_xy 0x0 +#define DC_linear_linear 0x80 +#define DC_zmode_nozcmp 0x0 +#define DC_zmode_ze 0x200 +#define DC_zmode_zne 0x300 +#define DC_zmode_zlt 0x400 +#define DC_zmode_zlte 0x500 +#define DC_zmode_zgt 0x600 +#define DC_zmode_zgte 0x700 +#define DC_solid_disable 0x0 +#define DC_solid_enable 0x800 +#define DC_arzero_disable 0x0 +#define DC_arzero_enable 0x1000 +#define DC_sgnzero_disable 0x0 +#define DC_sgnzero_enable 0x2000 +#define DC_shftzero_disable 0x0 +#define DC_shftzero_enable 0x4000 +#define DC_bop_SHIFT 16 +#define DC_trans_SHIFT 20 +#define DC_bltmod_bmonolef 0x0 +#define DC_bltmod_bmonowf 0x8000000 +#define DC_bltmod_bplan 0x2000000 +#define DC_bltmod_bfcol 0x4000000 +#define DC_bltmod_bu32bgr 0x6000000 +#define DC_bltmod_bu32rgb 0xe000000 +#define DC_bltmod_bu24bgr 0x16000000 +#define DC_bltmod_bu24rgb 0x1e000000 +#define DC_pattern_disable 0x0 +#define DC_pattern_enable 0x20000000 +#define DC_transc_disable 0x0 +#define DC_transc_enable 0x40000000 +#define DC_clipdis_disable 0x0 +#define DC_clipdis_enable 0x80000000 + +#define SETADD_mode_vertlist 0x0 + + +#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ + DC_solid_enable | DC_transc_enable) + + +#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ + DC_solid_disable | DC_arzero_disable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | \ + DC_pattern_disable | DC_transc_disable | \ + DC_clipdis_enable) \ + +#define MGA_FLUSH_CMD (DC_opcod_texture_trap | (0xF << DC_trans_SHIFT) |\ + DC_arzero_enable | DC_sgnzero_enable | \ + DC_atype_i) + #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c index d09881bad..32f6bcf4b 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c @@ -26,337 +26,1047 @@ * Authors: Jeff Hartmann <jhartmann@precisioninsight.com> * Keith Whitwell <keithw@precisioninsight.com> * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/mga_state.c,v 1.1 2000/02/11 17:26:08 dawes Exp $ + * $XFree86$ * */ #define __NO_VERSION__ #include "drmP.h" #include "mga_drv.h" -#include "mgareg_flags.h" -#include "mga_dma.h" -#include "mga_state.h" #include "drm.h" -void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) +static void mgaEmitClipRect( drm_mga_private_t *dev_priv, + drm_clip_rect_t *box ) { + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + /* This takes 10 dwords */ PRIMGETPTR( dev_priv ); + + /* Force reset of dwgctl (eliminates clip disable) */ +#if 1 + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, 0 ); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); +#else + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + PRIMOUTREG( MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000 ); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + PRIMOUTREG( MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000 ); +#endif - /* The G400 seems to have an issue with the second WARP not - * stalling clipper register writes. This bothers me, but the only - * way I could get it to never clip the last triangle under any - * circumstances is by inserting TWO dwgsync commands. - */ - if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); - } - + PRIMOUTREG( MGAREG_DMAPAD, 0 ); PRIMOUTREG( MGAREG_CXBNDRY, ((box->x2)<<16)|(box->x1) ); - PRIMOUTREG( MGAREG_YTOP, box->y1 * dev_priv->stride ); - PRIMOUTREG( MGAREG_YBOT, box->y2 * dev_priv->stride ); + PRIMOUTREG( MGAREG_YTOP, box->y1 * dev_priv->stride/2 ); + PRIMOUTREG( MGAREG_YBOT, box->y2 * dev_priv->stride/2 ); + PRIMADVANCE( dev_priv ); } - -static void mgaEmitContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static void mgaEmitContext(drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->ContextState; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + /* This takes a max of 15 dwords */ PRIMGETPTR( dev_priv ); + PRIMOUTREG( MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG] ); PRIMOUTREG( MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS] ); PRIMOUTREG( MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT] ); PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + PRIMOUTREG( MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL] ); PRIMOUTREG( MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR] ); PRIMOUTREG( MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG] ); + PRIMOUTREG( MGAREG_ZORG, dev_priv->depthOffset ); /* invarient */ if (dev_priv->chipset == MGA_CARD_TYPE_G400) { PRIMOUTREG( MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG] ); PRIMOUTREG( MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0] ); - PRIMOUTREG( MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1] ); - } + PRIMOUTREG( MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1] ); + PRIMOUTREG( MGAREG_FCOL, regs[MGA_CTXREG_FCOL] ); + } else { + PRIMOUTREG( MGAREG_FCOL, regs[MGA_CTXREG_FCOL] ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + } PRIMADVANCE( dev_priv ); } -static void mgaG200EmitTex( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitTex( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR( dev_priv ); - PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); - PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); - PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); - PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); - PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); - PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); - PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); - PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); - PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); - PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); - PRIMOUTREG(0x2d00 + 24*4, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(0x2d00 + 34*4, regs[MGA_TEXREG_HEIGHT] ); + /* This takes 20 dwords */ + + PRIMOUTREG( MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + PRIMOUTREG( MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + PRIMOUTREG( MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + PRIMOUTREG( MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + + PRIMOUTREG( MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + PRIMOUTREG( MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + PRIMOUTREG( MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + PRIMOUTREG( MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + + PRIMOUTREG( MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + PRIMOUTREG( MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + PRIMOUTREG( MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + PRIMOUTREG( 0x2d00 + 24*4, regs[MGA_TEXREG_WIDTH] ); + + PRIMOUTREG( 0x2d00 + 34*4, regs[MGA_TEXREG_HEIGHT] ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); PRIMADVANCE( dev_priv ); } -static void mgaG400EmitTex0( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex0( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; - int multitex = buf_priv->WarpPipe & MGA_T2; - + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; + int multitex = sarea_priv->WarpPipe & MGA_T2; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + PRIMGETPTR( dev_priv ); - - PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); - PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); - PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); - PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); - PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); - PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); - PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); - PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); - PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); - PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); - PRIMOUTREG(0x2d00 + 49*4, 0); - PRIMOUTREG(0x2d00 + 57*4, 0); - PRIMOUTREG(0x2d00 + 53*4, 0); - PRIMOUTREG(0x2d00 + 61*4, 0); + /* This takes a max of 30 dwords */ + + PRIMOUTREG( MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + PRIMOUTREG( MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + PRIMOUTREG( MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + PRIMOUTREG( MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + + PRIMOUTREG( MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + PRIMOUTREG( MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + PRIMOUTREG( MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + PRIMOUTREG( MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + + PRIMOUTREG( MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + PRIMOUTREG( MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + PRIMOUTREG( MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + PRIMOUTREG( 0x2d00 + 49*4, 0 ); + + PRIMOUTREG( 0x2d00 + 57*4, 0 ); + PRIMOUTREG( 0x2d00 + 53*4, 0 ); + PRIMOUTREG( 0x2d00 + 61*4, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); if (!multitex) { - PRIMOUTREG(0x2d00 + 52*4, 0x40 ); - PRIMOUTREG(0x2d00 + 60*4, 0x40 ); + PRIMOUTREG( 0x2d00 + 52*4, 0x40 ); + PRIMOUTREG( 0x2d00 + 60*4, 0x40 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); } - PRIMOUTREG(0x2d00 + 54*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); - PRIMOUTREG(0x2d00 + 62*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( 0x2d00 + 54*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); + PRIMOUTREG( 0x2d00 + 62*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); PRIMADVANCE( dev_priv ); } #define TMC_map1_enable 0x80000000 - -static void mgaG400EmitTex1( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex1( drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[1]; - PRIMLOCALS; - PRIMGETPTR(dev_priv); - - PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable); - PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); - PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); - PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); - PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); - PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); - PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); - PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); - PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); - PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); - PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + DRM_DEBUG("%s\n", __FUNCTION__); - PRIMOUTREG(0x2d00 + 49*4, 0); - PRIMOUTREG(0x2d00 + 57*4, 0); - PRIMOUTREG(0x2d00 + 53*4, 0); - PRIMOUTREG(0x2d00 + 61*4, 0); + PRIMGETPTR( dev_priv ); - PRIMOUTREG(0x2d00 + 52*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); - PRIMOUTREG(0x2d00 + 60*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + /* This takes 25 dwords */ - PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + PRIMOUTREG( MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable ); + PRIMOUTREG( MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + PRIMOUTREG( MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + PRIMOUTREG( MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); - PRIMADVANCE( dev_priv ); + PRIMOUTREG( MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + PRIMOUTREG( MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + PRIMOUTREG( MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + PRIMOUTREG( MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + + PRIMOUTREG( MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + PRIMOUTREG( MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + PRIMOUTREG( MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + PRIMOUTREG( 0x2d00 + 49*4, 0 ); + + PRIMOUTREG( 0x2d00 + 57*4, 0 ); + PRIMOUTREG( 0x2d00 + 53*4, 0 ); + PRIMOUTREG( 0x2d00 + 61*4, 0 ); + PRIMOUTREG( 0x2d00 + 52*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); + + PRIMOUTREG( 0x2d00 + 60*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); + PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); + PRIMOUTREG( MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + + PRIMADVANCE( dev_priv ); } +/* Required when switching from multitexturing to single texturing. + */ +static void mgaG400EmitTexFlush( drm_mga_private_t *dev_priv ) +{ + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + PRIMGETPTR( dev_priv ); + + /* This takes 15 dwords */ + + PRIMOUTREG( MGAREG_YDST, 0 ); + PRIMOUTREG( MGAREG_FXLEFT, 0 ); + PRIMOUTREG( MGAREG_FXRIGHT, 1 ); + PRIMOUTREG( MGAREG_DWGCTL, MGA_FLUSH_CMD ); + + PRIMOUTREG( MGAREG_LEN + MGAREG_MGA_EXEC, 1 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, 0x7000 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + + PRIMOUTREG( MGAREG_TEXCTL2, 0 ); + PRIMOUTREG( MGAREG_LEN + MGAREG_MGA_EXEC, 0 ); + PRIMOUTREG( MGAREG_TEXCTL2, 0x80 ); + PRIMOUTREG( MGAREG_LEN + MGAREG_MGA_EXEC, 0 ); -static void mgaG400EmitPipe(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) + PRIMADVANCE( dev_priv ); +} + +static void mgaG400EmitPipe( drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; float fParam = 12800.0f; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); - + PRIMGETPTR( dev_priv ); + + /* This takes 30 dwords */ + /* Establish vertex size. */ if (pipe & MGA_T2) { - PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001e09); - PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000); + PRIMOUTREG( MGAREG_WIADDR2, WIA_wmode_suspend ); + PRIMOUTREG( MGAREG_WVRTXSZ, 0x00001e09 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0x1e000000 ); } else { - PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807); - PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x18000000); - } - - PRIMOUTREG(MGAREG_WFLAG, 0); - PRIMOUTREG(MGAREG_WFLAG1, 0); - - PRIMOUTREG(0x2d00 + 56*4, *((u32 *)(&fParam))); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_WIADDR2, WIA_wmode_suspend ); + PRIMOUTREG( MGAREG_WVRTXSZ, 0x00001807 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0 ); + PRIMOUTREG( MGAREG_WACCEPTSEQ, 0x18000000 ); + } + + PRIMOUTREG( MGAREG_WFLAG, 0 ); + PRIMOUTREG( MGAREG_WFLAG1, 0 ); + PRIMOUTREG( 0x2d00 + 56*4, *((u32 *)(&fParam)) ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); - PRIMOUTREG(0x2d00 + 49*4, 0); /* Tex stage 0 */ - PRIMOUTREG(0x2d00 + 57*4, 0); /* Tex stage 0 */ - PRIMOUTREG(0x2d00 + 53*4, 0); /* Tex stage 1 */ - PRIMOUTREG(0x2d00 + 61*4, 0); /* Tex stage 1 */ + PRIMOUTREG( 0x2d00 + 49*4, 0 ); /* Tex stage 0 */ + PRIMOUTREG( 0x2d00 + 57*4, 0 ); /* Tex stage 0 */ + PRIMOUTREG( 0x2d00 + 53*4, 0 ); /* Tex stage 1 */ + PRIMOUTREG( 0x2d00 + 61*4, 0 ); /* Tex stage 1 */ - PRIMOUTREG(0x2d00 + 54*4, 0x40); /* Tex stage 0 : w */ - PRIMOUTREG(0x2d00 + 62*4, 0x40); /* Tex stage 0 : h */ - PRIMOUTREG(0x2d00 + 52*4, 0x40); /* Tex stage 1 : w */ - PRIMOUTREG(0x2d00 + 60*4, 0x40); /* Tex stage 1 : h */ + PRIMOUTREG( 0x2d00 + 54*4, 0x40 ); /* Tex stage 0 : w */ + PRIMOUTREG( 0x2d00 + 62*4, 0x40 ); /* Tex stage 0 : h */ + PRIMOUTREG( 0x2d00 + 52*4, 0x40 ); /* Tex stage 1 : w */ + PRIMOUTREG( 0x2d00 + 60*4, 0x40 ); /* Tex stage 1 : h */ /* Dma pading required due to hw bug */ - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR2, (dev_priv->WarpIndex[pipe].phys_addr | - WIA_wmode_start | WIA_wagp_agp)); - PRIMADVANCE(dev_priv); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_WIADDR2, (u32)(dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp) ); + PRIMADVANCE( dev_priv ); } -static void mgaG200EmitPipe( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitPipe( drm_mga_private_t *dev_priv ) { - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); - PRIMOUTREG(MGAREG_WVRTXSZ, 7); - PRIMOUTREG(MGAREG_WFLAG, 0); - PRIMOUTREG(0x2d00 + 24*4, 0); /* tex w/h */ + PRIMGETPTR( dev_priv ); - PRIMOUTREG(0x2d00 + 25*4, 0x100); - PRIMOUTREG(0x2d00 + 34*4, 0); /* tex w/h */ - PRIMOUTREG(0x2d00 + 42*4, 0xFFFF); - PRIMOUTREG(0x2d00 + 60*4, 0xFFFF); + /* This takes 15 dwords */ + + PRIMOUTREG( MGAREG_WIADDR, WIA_wmode_suspend ); + PRIMOUTREG( MGAREG_WVRTXSZ, 7 ); + PRIMOUTREG( MGAREG_WFLAG, 0 ); + PRIMOUTREG( 0x2d00 + 24*4, 0 ); /* tex w/h */ + + PRIMOUTREG( 0x2d00 + 25*4, 0x100 ); + PRIMOUTREG( 0x2d00 + 34*4, 0 ); /* tex w/h */ + PRIMOUTREG( 0x2d00 + 42*4, 0xFFFF ); + PRIMOUTREG( 0x2d00 + 60*4, 0xFFFF ); /* Dma pading required due to hw bug */ - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR, (dev_priv->WarpIndex[pipe].phys_addr | - WIA_wmode_start | WIA_wagp_agp)); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_DMAPAD, 0xffffffff ); + PRIMOUTREG( MGAREG_WIADDR, (u32)(dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp) ); - PRIMADVANCE(dev_priv); + PRIMADVANCE( dev_priv ); } -void mgaEmitState( drm_mga_private_t *dev_priv, drm_mga_buf_priv_t *buf_priv ) +static void mgaEmitState( drm_mga_private_t *dev_priv ) { - unsigned int dirty = buf_priv->dirty; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + DRM_DEBUG("%s\n", __FUNCTION__); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - if (dirty & MGASAREA_NEW_CONTEXT) - mgaEmitContext( dev_priv, buf_priv ); + int multitex = sarea_priv->WarpPipe & MGA_T2; - if (dirty & MGASAREA_NEW_TEX1) - mgaG400EmitTex1( dev_priv, buf_priv ); - - if (dirty & MGASAREA_NEW_TEX0) - mgaG400EmitTex0( dev_priv, buf_priv ); + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + if ((dev_priv->WarpPipe & MGA_T2) && !multitex) { + mgaG400EmitTexFlush( dev_priv ); + } + mgaG400EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } + + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } - if (dirty & MGASAREA_NEW_PIPE) - mgaG400EmitPipe( dev_priv, buf_priv ); + if (dirty & MGA_UPLOAD_TEX0) { + mgaG400EmitTex0( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + + if ((dirty & MGA_UPLOAD_TEX1) && multitex) { + mgaG400EmitTex1( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX1; + } } else { - if (dirty & MGASAREA_NEW_CONTEXT) - mgaEmitContext( dev_priv, buf_priv ); + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG200EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } - if (dirty & MGASAREA_NEW_TEX0) - mgaG200EmitTex( dev_priv, buf_priv ); + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } - if (dirty & MGASAREA_NEW_PIPE) - mgaG200EmitPipe( dev_priv, buf_priv ); - } + if (dirty & MGA_UPLOAD_TEX0) { + mgaG200EmitTex( dev_priv ); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + } } - /* Disallow all write destinations except the front and backbuffer. */ -static int mgaCopyContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static int mgaVerifyContext(drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; - - if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOrg && - regs[MGA_CTXREG_DSTORG] != dev_priv->backOrg) + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && + regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { + DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", + regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset, + dev_priv->backOffset); + regs[MGA_CTXREG_DSTORG] = 0; return -1; + } - memcpy(buf_priv->ContextState, sarea_priv->ContextState, - sizeof(buf_priv->ContextState)); return 0; } - /* Disallow texture reads from PCI space. */ -static int mgaCopyTex(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv, +static int mgaVerifyTex(drm_mga_private_t *dev_priv, int unit) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) - return -1; + DRM_DEBUG("%s\n", __FUNCTION__); - memcpy(buf_priv->TexState[unit], sarea_priv->TexState[unit], - sizeof(buf_priv->TexState[0])); + if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { + DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", + sarea_priv->TexState[unit][MGA_TEXREG_ORG], + unit); + sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0; + return -1; + } return 0; } - -int mgaCopyAndVerifyState( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static int mgaVerifyState( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned int dirty = sarea_priv->dirty ; + unsigned int dirty = sarea_priv->dirty; int rv = 0; - buf_priv->dirty = sarea_priv->dirty; - buf_priv->WarpPipe = sarea_priv->WarpPipe; + DRM_DEBUG("%s\n", __FUNCTION__); + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; - if (dirty & MGASAREA_NEW_CONTEXT) - rv |= mgaCopyContext( dev_priv, buf_priv ); + if (dirty & MGA_UPLOAD_CTX) + rv |= mgaVerifyContext( dev_priv ); - if (dirty & MGASAREA_NEW_TEX0) - rv |= mgaCopyTex( dev_priv, buf_priv, 0 ); + if (dirty & MGA_UPLOAD_TEX0) + rv |= mgaVerifyTex( dev_priv, 0 ); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - if (dirty & MGASAREA_NEW_TEX1) - rv |= mgaCopyTex( dev_priv, buf_priv, 1 ); + if (dirty & MGA_UPLOAD_TEX1) + rv |= mgaVerifyTex( dev_priv, 1 ); - if (dirty & MGASAREA_NEW_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G400_PIPES); + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES); } else { - if (dirty & MGASAREA_NEW_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G200_PIPES); + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES); } return rv == 0; } +static int mgaVerifyIload( drm_mga_private_t *dev_priv, + unsigned long bus_address, + unsigned int dstOrg, int length ) +{ + DRM_DEBUG("%s\n", __FUNCTION__); + + if(dstOrg < dev_priv->textureOffset || + dstOrg + length > + (dev_priv->textureOffset + dev_priv->textureSize)) { + return -EINVAL; + } + if(length % 64) { + return -EINVAL; + } + return 0; +} + +/* This copies a 64 byte aligned agp region to the frambuffer + * with a standard blit, the ioctl needs to do checking */ + +static void mga_dma_dispatch_tex_blit( drm_device_t *dev, + unsigned long bus_address, + int length, + unsigned int destOrg ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + int use_agp = PDEA_pagpxfer_enable | 0x00000001; + u16 y2; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + y2 = length / 64; + + PRIM_OVERFLOW( dev, dev_priv, 30 ); + PRIMGETPTR( dev_priv ); + + PRIMOUTREG( MGAREG_DSTORG, destOrg ); + PRIMOUTREG( MGAREG_MACCESS, 0x00000000 ); + DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp); + PRIMOUTREG( MGAREG_SRCORG, (u32) bus_address | use_agp ); + PRIMOUTREG( MGAREG_AR5, 64 ); + + PRIMOUTREG( MGAREG_PITCH, 64 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGCTL, MGA_COPY_CMD ); + + PRIMOUTREG( MGAREG_AR0, 63 ); + PRIMOUTREG( MGAREG_AR3, 0 ); + PRIMOUTREG( MGAREG_FXBNDRY, (63 << 16) ); + PRIMOUTREG( MGAREG_YDSTLEN+MGAREG_MGA_EXEC, y2 ); + + PRIMOUTREG( MGAREG_SRCORG, 0 ); + PRIMOUTREG( MGAREG_PITCH, dev_priv->stride / dev_priv->cpp ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMADVANCE( dev_priv ); +} + +static void mga_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long address = (unsigned long)buf->bus_address; + int length = buf->used; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + int primary_needed; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("dispatch vertex %d addr 0x%lx, " + "length 0x%x nbox %d dirty %x\n", + buf->idx, address, length, + sarea_priv->nbox, sarea_priv->dirty); + + DRM_DEBUG("used : %d, total : %d\n", buf->used, buf->total); + if(sarea_priv->WarpPipe & MGA_T2) { + if ((buf->used/4) % 10) + DRM_DEBUG("Multitex Buf is not aligned properly!!!\n"); + } else { + if ((buf->used/4) % 8) + DRM_DEBUG("Buf is not aligned properly!!!\n"); + } + + if (buf->used) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + primary_needed = (30+15+15+30+25+ + 10 + + 15 * MGA_NR_SAREA_CLIPRECTS); + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + mgaEmitState( dev_priv ); + + do { + if (i < sarea_priv->nbox) { + DRM_DEBUG("idx %d Emit box %d/%d:" + "%d,%d - %d,%d\n", + buf->idx, + i, sarea_priv->nbox, + sarea_priv->boxes[i].x1, + sarea_priv->boxes[i].y1, + sarea_priv->boxes[i].x2, + sarea_priv->boxes[i].y2); + + mgaEmitClipRect( dev_priv, + &sarea_priv->boxes[i] ); + } + + PRIMGETPTR( dev_priv ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_SECADDRESS, + ((u32)address) | TT_VERTEX ); + PRIMOUTREG( MGAREG_SECEND, + (((u32)(address + length)) | use_agp) ); + PRIMADVANCE( dev_priv ); + } while (++i < sarea_priv->nbox); + } + + if (buf_priv->discard) { + if (buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + + +} + + +static void mga_dma_dispatch_indices(drm_device_t *dev, + drm_buf_t *buf, + unsigned int start, + unsigned int end) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int address = (unsigned int)buf->bus_address; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + int primary_needed; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("dispatch indices %d addr 0x%x, " + "start 0x%x end 0x%x nbox %d dirty %x\n", + buf->idx, address, start, end, + sarea_priv->nbox, sarea_priv->dirty); + + if (start != end) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + primary_needed = (25+15+30+25+ + 10 + + 15 * MGA_NR_SAREA_CLIPRECTS); + PRIM_OVERFLOW( dev, dev_priv, primary_needed ); + mgaEmitState( dev_priv ); + + do { + if (i < sarea_priv->nbox) { + DRM_DEBUG("idx %d Emit box %d/%d:" + "%d,%d - %d,%d\n", + buf->idx, + i, sarea_priv->nbox, + sarea_priv->boxes[i].x1, + sarea_priv->boxes[i].y1, + sarea_priv->boxes[i].x2, + sarea_priv->boxes[i].y2); + + mgaEmitClipRect( dev_priv, + &sarea_priv->boxes[i] ); + } + PRIMGETPTR( dev_priv ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_SETUPADDRESS, + ((address + start) | + SETADD_mode_vertlist) ); + PRIMOUTREG( MGAREG_SETUPEND, + ((address + end) | use_agp) ); + PRIMADVANCE( dev_priv ); + } while (++i < sarea_priv->nbox); + } + if (buf_priv->discard) { + if (buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } +} + + +static void mga_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + unsigned int cmd; + int i; + int primary_needed; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + if ( dev_priv->sgram ) + cmd = MGA_CLEAR_CMD | DC_atype_blk; + else + cmd = MGA_CLEAR_CMD | DC_atype_rstr; + + primary_needed = nbox * 70; + if (primary_needed == 0) primary_needed = 70; + PRIM_OVERFLOW( dev, dev_priv, primary_needed ); + PRIMGETPTR( dev_priv ); + + for (i = 0 ; i < nbox ; i++) { + unsigned int height = pbox[i].y2 - pbox[i].y1; + + DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n", + pbox[i].x1, pbox[i].y1, pbox[i].x2, + pbox[i].y2, flags); + + if ( flags & MGA_FRONT ) { + DRM_DEBUG("clear front\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG( MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_FCOL, clear_color ); + PRIMOUTREG( MGAREG_DSTORG, dev_priv->frontOffset ); + PRIMOUTREG( MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_BACK ) { + DRM_DEBUG("clear back\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_YDSTLEN, (pbox[i].y1<<16)|height ); + PRIMOUTREG( MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1 ); + + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_FCOL, clear_color ); + PRIMOUTREG( MGAREG_DSTORG, dev_priv->backOffset ); + PRIMOUTREG( MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_DEPTH ) { + DRM_DEBUG("clear depth\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_YDSTLEN, (pbox[i].y1<<16)|height ); + PRIMOUTREG( MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1 ); + + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_FCOL, clear_zval ); + PRIMOUTREG( MGAREG_DSTORG, dev_priv->depthOffset ); + PRIMOUTREG( MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + } + + /* Force reset of DWGCTL */ + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + PRIMADVANCE( dev_priv ); +} + +static void mga_dma_dispatch_swap( drm_device_t *dev ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int i; + int primary_needed; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + primary_needed = nbox * 5; + primary_needed += 60; + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIMGETPTR( dev_priv ); + + PRIMOUTREG( MGAREG_DSTORG, dev_priv->frontOffset ); + PRIMOUTREG( MGAREG_MACCESS, dev_priv->mAccess ); + PRIMOUTREG( MGAREG_SRCORG, dev_priv->backOffset ); + PRIMOUTREG( MGAREG_AR5, dev_priv->stride/2 ); + + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DWGCTL, MGA_COPY_CMD ); + + for (i = 0 ; i < nbox; i++) { + unsigned int h = pbox[i].y2 - pbox[i].y1; + unsigned int start = pbox[i].y1 * dev_priv->stride/2; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox[i].x1, pbox[i].y1, + pbox[i].x2, pbox[i].y2); + + PRIMOUTREG( MGAREG_AR0, start + pbox[i].x2 - 1 ); + PRIMOUTREG( MGAREG_AR3, start + pbox[i].x1 ); + PRIMOUTREG( MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16) ); + PRIMOUTREG( MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h ); + } + + /* Force reset of DWGCTL */ + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0 ); + PRIMOUTREG( MGAREG_SRCORG, 0 ); + PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + + PRIMADVANCE( dev_priv ); +} + +int mga_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_clear_t clear; + + copy_from_user_ret(&clear, (drm_mga_clear_t *)arg, sizeof(clear), + -EFAULT); + DRM_DEBUG("%s\n", __FUNCTION__); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_clear_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + DRM_DEBUG("%s\n", __FUNCTION__); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_swap_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_swap( dev ); + PRIMUPDATE(dev_priv); + set_bit(MGA_BUF_SWAP_PENDING, &dev_priv->current_prim->buffer_status); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_iload(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_iload_t iload; + unsigned long bus_address; + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("Starting Iload\n"); + copy_from_user_ret(&iload, (drm_mga_iload_t *)arg, sizeof(iload), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_iload called without lock held\n"); + return -EINVAL; + } + + buf = dma->buflist[ iload.idx ]; + buf_priv = buf->dev_private; + bus_address = buf->bus_address; + DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n", + bus_address, iload.length, iload.destOrg); + + if(mgaVerifyIload(dev_priv, + bus_address, + iload.destOrg, + iload.length)) { + mga_freelist_put(dev, buf); + return -EINVAL; + } + + sarea_priv->dirty |= MGA_UPLOAD_CTX; + + mga_dma_dispatch_tex_blit(dev, bus_address, iload.length, + iload.destOrg); + AGEBUF(dev_priv, buf_priv); + buf_priv->discard = 1; + mga_freelist_put(dev, buf); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_vertex_t vertex; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&vertex, (drm_mga_vertex_t *)arg, sizeof(vertex), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_vertex\n"); + + buf = dma->buflist[ vertex.idx ]; + buf_priv = buf->dev_private; + + buf->used = vertex.used; + buf_priv->discard = vertex.discard; + + if (!mgaVerifyState(dev_priv)) { + if (vertex.discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + DRM_DEBUG("bad state\n"); + return -EINVAL; + } + + mga_dma_dispatch_vertex(dev, buf); + + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + + +int mga_indices(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_indices_t indices; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&indices, (drm_mga_indices_t *)arg, sizeof(indices), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_indices called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_indices\n"); + + buf = dma->buflist[ indices.idx ]; + buf_priv = buf->dev_private; + + buf_priv->discard = indices.discard; + + if (!mgaVerifyState(dev_priv)) { + if (indices.discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + return -EINVAL; + } + + mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); + + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + + + +static int mga_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) +{ + int i; + drm_buf_t *buf; + DRM_DEBUG("%s\n", __FUNCTION__); + + for (i = d->granted_count; i < d->request_count; i++) { + buf = mga_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; +} + +int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_dma called without lock held\n"); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + if (d.request_count < 0 || d.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count); + return -EINVAL; + } + + d.granted_count = 0; + + if (d.request_count) { + retcode = mga_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + return retcode; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c index 54aba58c4..392abceb9 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c @@ -1,8 +1,7 @@ /* proc.c -- /proc support for DRM -*- linux-c -*- * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com - * Revised: Sun Feb 13 23:41:04 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -164,7 +163,10 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, { drm_device_t *dev = (drm_device_t *)data; drm_map_t *map; - const char *types[] = { "FB", "REG", "SHM" }; + /* Hardcoded from _DRM_FRAME_BUFFER, + _DRM_REGISTERS, _DRM_SHM, and + _DRM_AGP. */ + const char *types[] = { "FB", "REG", "SHM", "AGP" }; const char *type; int i; @@ -175,7 +177,7 @@ static int _drm_vm_info(char *buf, char **start, off_t offset, int len, "address mtrr\n\n"); for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->type < 0 || map->type > 2) type = "??"; + if (map->type < 0 || map->type > 3) type = "??"; else type = types[map->type]; DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", i, @@ -397,6 +399,7 @@ static int _drm_vma_info(char *buf, char **start, off_t offset, int len, pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); #endif DRM_PROC_PRINT("\n"); +#if 0 for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) { pgd = pgd_offset(vma->vm_mm, i); pmd = pmd_offset(pgd, i); @@ -417,6 +420,7 @@ static int _drm_vma_info(char *buf, char **start, off_t offset, int len, DRM_PROC_PRINT(" 0x%08lx\n", i); } } +#endif } return len; diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_bufs.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_bufs.c new file mode 100644 index 000000000..bad6c5714 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_bufs.c @@ -0,0 +1,309 @@ +/* r128_bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Wed Apr 12 16:19:08 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <kevin@precisioninsight.com> + * Rickard E. (Rik) Faith <faith@precisioninsight.com> + * Jeff Hartmann <jhartmann@precisioninsight.com> + * + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" +#include "linux/un.h" + + +#ifdef DRM_AGP +int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = dev->agp->base + request.agp_start; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + for (offset = 0; + entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + offset); + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_priv_size = sizeof(drm_r128_buf_priv_t); + buf->dev_private = drm_alloc(sizeof(drm_r128_buf_priv_t), + DRM_MEM_BUFS); + memset(buf->dev_private, 0, buf->dev_priv_size); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + dma->flags = _DRM_DMA_USE_AGP; + + atomic_dec(&dev->buf_alloc); + return 0; +} +#endif + +int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_buf_desc_t request; + + if (!dev_priv || dev_priv->is_pci) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + +#ifdef DRM_AGP + if (request.flags & _DRM_AGP_BUFFER) + return r128_addbufs_agp(inode, filp, cmd, arg); + else +#endif + return -EINVAL; +} + +int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_map_t *)arg, + sizeof(request), + -EFAULT); + + if (request.count >= dma->buf_count) { + if (dma->flags & _DRM_DMA_USE_AGP) { + drm_map_t *map; + + map = dev_priv->agp_vertbufs; + if (!map) { + retcode = -EINVAL; + goto done; + } + + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } + if (virtual > -1024UL) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return retcode; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_context.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_context.c new file mode 100644 index 000000000..d288fd284 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_context.c @@ -0,0 +1,214 @@ +/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * + * $XFree86$ + * + */ + +#include <linux/sched.h> + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +extern drm_ctx_t r128_res_ctx; + +static int r128_alloc_queue(drm_device_t *dev) +{ +#if 0 + static int context = 0; +#endif + + return drm_ctxbitmap_next(dev); +} + +int r128_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + r128_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int r128_context_switch_complete(drm_device_t *dev, int new) +{ + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + /* If a context switch is ever initiated + when the kernel holds the lock, release + that lock here. */ +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() + - dev->ctx_start)]); + +#endif + clear_bit(0, &dev->context_flag); + wake_up(&dev->context_wait); + + return 0; +} + + +int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + + +int r128_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = r128_alloc_queue(dev); + } + DRM_DEBUG("%d\n", ctx.handle); + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int r128_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (ctx.flags==_DRM_CONTEXT_PRESERVED) + r128_res_ctx.handle=ctx.handle; + return 0; +} + +int r128_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + /* This is 0, because we don't hanlde any context flags */ + ctx.flags = 0; + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int r128_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return r128_context_switch(dev, dev->last_context, ctx.handle); +} + +int r128_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + r128_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int r128_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + drm_ctxbitmap_free(dev, ctx.handle); + + return 0; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_dma.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_dma.c new file mode 100644 index 000000000..860c41885 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_dma.c @@ -0,0 +1,908 @@ +/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +#include <linux/interrupt.h> /* For task queue support */ +#include <linux/delay.h> + + + +#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) + +#define DO_REMAPFREE(_m) \ + do { \ + if ((_m)->handle && (_m)->size) \ + drm_ioremapfree((_m)->handle, (_m)->size); \ + } while (0) + +#define DO_FIND_MAP(_m, _o) \ + do { \ + int _i; \ + for (_i = 0; _i < dev->map_count; _i++) { \ + if (dev->maplist[_i]->offset == _o) { \ + _m = dev->maplist[_i]; \ + break; \ + } \ + } \ + } while (0) + + +#define R128_MAX_VBUF_AGE 0x10000000 +#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 + +int R128_READ_PLL(drm_device_t *dev, int addr) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); + return R128_READ(R128_CLOCK_CNTL_DATA); +} + +static void r128_flush_write_combine(void) +{ + int xchangeDummy; + + __asm__ volatile("push %%eax ;" + "xchg %%eax, %0 ;" + "pop %%eax" : : "m" (xchangeDummy)); + __asm__ volatile("push %%eax ;" + "push %%ebx ;" + "push %%ecx ;" + "push %%edx ;" + "movl $0,%%eax ;" + "cpuid ;" + "pop %%edx ;" + "pop %%ecx ;" + "pop %%ebx ;" + "pop %%eax" : /* no outputs */ : /* no inputs */ ); +} + +static int r128_do_cleanup_cce(drm_device_t *dev) +{ + if (dev->dev_private) { + drm_r128_private_t *dev_priv = dev->dev_private; + + if (!dev_priv->is_pci) { + DO_REMAPFREE(dev_priv->agp_ring); + DO_REMAPFREE(dev_priv->agp_read_ptr); + DO_REMAPFREE(dev_priv->agp_vertbufs); + DO_REMAPFREE(dev_priv->agp_indbufs); + DO_REMAPFREE(dev_priv->agp_textures); + } + + drm_free(dev->dev_private, sizeof(drm_r128_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + } + + return 0; +} + +static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init) +{ + drm_r128_private_t *dev_priv; + int i; + + dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *)dev_priv; + + memset(dev_priv, 0, sizeof(drm_r128_private_t)); + + dev_priv->is_pci = init->is_pci; + + dev_priv->usec_timeout = init->usec_timeout; + if (dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + dev_priv->cce_mode = init->cce_mode; + dev_priv->cce_fifo_size = init->cce_fifo_size; + dev_priv->cce_is_bm_mode = + ((init->cce_mode == R128_PM4_192BM) || + (init->cce_mode == R128_PM4_128BM_64INDBM) || + (init->cce_mode == R128_PM4_64BM_128INDBM) || + (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM)); + dev_priv->cce_secure = init->cce_secure; + + if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + for (i = 0; i < dev->map_count; i++) { + if (dev->maplist[i]->type == _DRM_SHM) { + dev_priv->sarea = dev->maplist[i]; + break; + } + } + + DO_FIND_MAP(dev_priv->fb, init->fb_offset); + if (!dev_priv->is_pci) { + DO_FIND_MAP(dev_priv->agp_ring, init->agp_ring_offset); + DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset); + DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset); + DO_FIND_MAP(dev_priv->agp_indbufs, init->agp_indbufs_offset); + DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset); + } + DO_FIND_MAP(dev_priv->mmio, init->mmio_offset); + + dev_priv->sarea_priv = + (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + + init->sarea_priv_offset); + + if (!dev_priv->is_pci) { + DO_REMAP(dev_priv->agp_ring); + DO_REMAP(dev_priv->agp_read_ptr); + DO_REMAP(dev_priv->agp_vertbufs); +#if 0 + DO_REMAP(dev_priv->agp_indirectbufs); + DO_REMAP(dev_priv->agp_textures); +#endif + + dev_priv->ring_size = init->ring_size; + dev_priv->ring_sizel2qw = drm_order(init->ring_size/8); + dev_priv->ring_entries = init->ring_size/sizeof(u32); + dev_priv->ring_read_ptr = ((__volatile__ u32 *) + dev_priv->agp_read_ptr->handle); + dev_priv->ring_start = (u32 *)dev_priv->agp_ring->handle; + dev_priv->ring_end = ((u32 *)dev_priv->agp_ring->handle + + dev_priv->ring_entries); + } + + dev_priv->submit_age = 0; + R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age); + + return 0; +} + +int r128_init_cce(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_init_t init; + + copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init), + -EFAULT); + + switch (init.func) { + case R128_INIT_CCE: + return r128_do_init_cce(dev, &init); + case R128_CLEANUP_CCE: + return r128_do_cleanup_cce(dev); + } + + return -EINVAL; +} + +static void r128_mark_vertbufs_done(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[i]; + drm_r128_buf_priv_t *buf_priv = buf->dev_private; + buf_priv->age = 0; + } +} + +static int r128_do_pixcache_flush(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp; + int i; + + tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL; + R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) + return 0; + udelay(1); + } + + return -EBUSY; +} + +static int r128_do_wait_for_fifo(drm_device_t *dev, int entries) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; + if (slots >= entries) return 0; + udelay(1); + } + return -EBUSY; +} + +static int r128_do_wait_for_idle(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i, ret; + + if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) { + (void)r128_do_pixcache_flush(dev); + return 0; + } + udelay(1); + } + return -EBUSY; +} + +int r128_do_engine_reset(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; + + (void)r128_do_pixcache_flush(dev); + + clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX); + mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL); + + R128_WRITE_PLL(R128_MCLK_CNTL, + mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CPP); + + gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL); + + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); + (void)R128_READ(R128_GEN_RESET_CNTL); + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI); + (void)R128_READ(R128_GEN_RESET_CNTL); + + R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl); + R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index); + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl); + + /* For CCE ring buffer only */ + if (dev_priv->cce_is_bm_mode) { + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); + R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); + *dev_priv->ring_read_ptr = 0; + dev_priv->sarea_priv->ring_write = 0; + } + + /* Reset the CCE mode */ + (void)r128_do_wait_for_idle(dev); + R128_WRITE(R128_PM4_BUFFER_CNTL, + dev_priv->cce_mode | dev_priv->ring_sizel2qw); + (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ + R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); + + r128_mark_vertbufs_done(dev); + return 0; +} + +int r128_eng_reset(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_eng_reset called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_engine_reset(dev); +} + +static int r128_do_engine_flush(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp; + + tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR); + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE); + + return 0; +} + +int r128_eng_flush(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_eng_flush called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_engine_flush(dev); +} + +static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK; + if (slots >= entries) return 0; + udelay(1); + } + return -EBUSY; +} + +int r128_do_cce_wait_for_idle(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + if (dev_priv->cce_is_bm_mode) { + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) { + int pm4stat = R128_READ(R128_PM4_STAT); + if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size && + !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { + return r128_do_pixcache_flush(dev); + } + } + udelay(1); + } + return -EBUSY; + } else { + int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size); + if (ret < 0) return ret; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int pm4stat = R128_READ(R128_PM4_STAT); + if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { + return r128_do_pixcache_flush(dev); + } + udelay(1); + } + return -EBUSY; + } +} + +int r128_cce_idle(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_wait_idle called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_cce_wait_for_idle(dev); +} + +static int r128_submit_packets_ring_secure(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + u32 tmp = 0; + int psize = 0; + int writing = 1; + int timeout; + + while (c > 0) { + tmp = *commands++; + if (!psize) { + writing = 1; + + if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= + (0x1004 << 9)) { + if ((tmp & R128_CCE_PACKET1_REG1_MASK) != + (R128_PM4_VC_FPU_SETUP << 9)) { + writing = 0; + } + } + psize = 3; + } else { + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } + } + psize--; + + if (writing) { + write++; + *write_ptr++ = tmp; + } + if (write >= dev_priv->ring_entries) { + write = 0; + write_ptr = dev_priv->ring_start; + } + timeout = 0; + while (write == *dev_priv->ring_read_ptr) { + (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); + if (timeout++ >= dev_priv->usec_timeout) + return -EBUSY; + udelay(1); + } + c--; + } + + if (write < 32) + memcpy(dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32)); + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + + *count = 0; + + return 0; +} + +static int r128_submit_packets_pio_secure(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp = 0; + int psize = 0; + int writing = 1; + int addr = R128_PM4_FIFO_DATA_EVEN; + int ret; + + while (*count > 0) { + tmp = *commands++; + if (!psize) { + writing = 1; + + if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= + (0x1004 << 9)) { + if ((tmp & R128_CCE_PACKET1_REG1_MASK) != + (R128_PM4_VC_FPU_SETUP << 9)) { + writing = 0; + } + } + psize = 3; + } else { + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } + } + psize--; + + if (writing) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) + return ret; + R128_WRITE(addr, tmp); + addr ^= 0x0004; + } + + *count -= 1; + } + + if (addr == R128_PM4_FIFO_DATA_ODD) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret; + R128_WRITE(addr, R128_CCE_PACKET2); + } + + return 0; +} + +static int r128_submit_packets_ring(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + int timeout; + + while (c > 0) { + write++; + *write_ptr++ = *commands++; + if (write >= dev_priv->ring_entries) { + write = 0; + write_ptr = dev_priv->ring_start; + } + timeout = 0; + while (write == *dev_priv->ring_read_ptr) { + (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); + if (timeout++ >= dev_priv->usec_timeout) + return -EBUSY; + udelay(1); + } + c--; + } + + if (write < 32) + memcpy(dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32)); + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + + *count = 0; + + return 0; +} + +static int r128_submit_packets_pio(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int ret; + + while (*count > 1) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; + R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); + R128_WRITE(R128_PM4_FIFO_DATA_ODD, *commands++); + *count -= 2; + } + + if (*count) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; + R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); + R128_WRITE(R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2); + *count = 0; + } + + return 0; +} + +static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int c = count; + int ret; + + if (dev_priv->cce_is_bm_mode) { + int left = 0; + + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + left = count - c; + } + + /* Since this is only used by the kernel we can use the + insecure ring buffer submit packet routine */ + ret = r128_submit_packets_ring(dev, buffer, &c); + + c += left; + } else { + /* Since this is only used by the kernel we can use the + insecure PIO submit packet routine */ + ret = r128_submit_packets_pio(dev, buffer, &c); + } + + if (ret < 0) return ret; + else return c; +} + +int r128_submit_pkt(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_packet_t packet; + u32 *buffer; + int c; + int size; + int ret = 0; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_submit_pkt called without holding the lock\n"); + return -EINVAL; + } + + copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet), + -EFAULT); + + c = packet.count; + size = c * sizeof(*buffer); + + if (dev_priv->cce_is_bm_mode) { + int left = 0; + + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + size = c * sizeof(*buffer); + left = packet.count - c; + } + + if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; + copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + + if (dev_priv->cce_secure) + ret = r128_submit_packets_ring_secure(dev, buffer, &c); + else + ret = r128_submit_packets_ring(dev, buffer, &c); + + c += left; + } else { + if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; + copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + + if (dev_priv->cce_secure) + ret = r128_submit_packets_pio_secure(dev, buffer, &c); + else + ret = r128_submit_packets_pio(dev, buffer, &c); + } + + kfree(buffer); + + packet.count = c; + copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet), + -EFAULT); + + if (ret) return ret; + else if (c > 0) return -EAGAIN; + + return 0; +} + +static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, ret; + u32 cce[2]; + + /* Make sure we have valid data */ + for (i = 0; i < v->send_count; i++) { + int idx = v->send_indices[i]; + + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + if (buf->pending) { + DRM_ERROR("Sending pending buffer:" + " buffer %d, offset %d\n", + v->send_indices[i], i); + return -EINVAL; + } + } + + /* Wait for idle, if we've wrapped to make sure that all pending + buffers have been processed */ + if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { + if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret; + dev_priv->submit_age = 0; + r128_mark_vertbufs_done(dev); + } + + /* Make sure WC cache has been flushed (if in PIO mode) */ + if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); + + /* FIXME: Add support for sending vertex buffer to the CCE here + instead of in client code. The v->prim holds the primitive + type that should be drawn. Loop over the list buffers in + send_indices[] and submit a packet for each VB. + + This will require us to loop over the clip rects here as + well, which implies that we extend the kernel driver to allow + cliprects to be stored here. Note that the cliprects could + possibly come from the X server instead of the client, but + this will require additional changes to the DRI to allow for + this optimization. */ + + /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ + cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); + cce[1] = dev_priv->submit_age; + if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) { + /* Until we add support for sending VBs to the CCE in + this routine, we can recover from this error. After + we add that support, we won't be able to easily + recover, so we will probably have to implement + another mechanism for handling timeouts from packets + submitted directly by the kernel. */ + return ret; + } + + /* Now that the submit packet request has succeeded, we can mark + the buffers as pending */ + for (i = 0; i < v->send_count; i++) { + buf = dma->buflist[v->send_indices[i]]; + buf->pending = 1; + + buf_priv = buf->dev_private; + buf_priv->age = dev_priv->submit_age; + } + + dev_priv->submit_age++; + + return 0; +} + +static drm_buf_t *r128_freelist_get(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, t; + + /* FIXME: Optimize -- use freelist code */ + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if (buf->pid == 0) return buf; + } + + for (t = 0; t < dev_priv->usec_timeout; t++) { + u32 done_age = R128_READ(R128_VB_AGE_REG); + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if (buf->pending && buf_priv->age <= done_age) { + /* The buffer has been processed, so it + can now be used */ + buf->pending = 0; + return buf; + } + } + udelay(1); + } + + return NULL; +} + + +static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) +{ + drm_buf_t *buf; + int i; + + for (i = v->granted_count; i < v->request_count; i++) { + buf = r128_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&v->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&v->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++v->granted_count; + } + return 0; +} + +int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_r128_vertex_t v; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_vertex_buf called without holding the lock\n"); + return -EINVAL; + } + + if (!dev_priv || dev_priv->is_pci) { + DRM_ERROR("r128_vertex_buf called with a PCI card\n"); + return -EINVAL; + } + + copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT); + DRM_DEBUG("%d: %d send, %d req\n", + current->pid, v.send_count, v.request_count); + + if (v.send_count < 0 || v.send_count > dma->buf_count) { + DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", + current->pid, v.send_count, dma->buf_count); + return -EINVAL; + } + if (v.request_count < 0 || v.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, v.request_count, dma->buf_count); + return -EINVAL; + } + + if (v.send_count) { + retcode = r128_send_vertbufs(dev, &v); + } + + v.granted_count = 0; + + if (!retcode && v.request_count) { + retcode = r128_get_vertbufs(dev, &v); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, v.granted_count); + copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT); + + return retcode; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drm.h new file mode 100644 index 000000000..fa90d72db --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drm.h @@ -0,0 +1,111 @@ +/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + */ + +#ifndef _R128_DRM_H_ +#define _R128_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmR128.h) + */ +typedef struct drm_r128_init { + enum { + R128_INIT_CCE = 0x01, + R128_CLEANUP_CCE = 0x02 + } func; + int sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_fifo_size; + int cce_secure; + int ring_size; + int usec_timeout; + + int fb_offset; + int agp_ring_offset; + int agp_read_ptr_offset; + int agp_vertbufs_offset; + int agp_indbufs_offset; + int agp_textures_offset; + int mmio_offset; +} drm_r128_init_t; + +typedef struct drm_r128_packet { + unsigned long *buffer; + int count; + int flags; +} drm_r128_packet_t; + +typedef enum drm_r128_prim { + _DRM_R128_PRIM_NONE = 0x0001, + _DRM_R128_PRIM_POINT = 0x0002, + _DRM_R128_PRIM_LINE = 0x0004, + _DRM_R128_PRIM_POLY_LINE = 0x0008, + _DRM_R128_PRIM_TRI_LIST = 0x0010, + _DRM_R128_PRIM_TRI_FAN = 0x0020, + _DRM_R128_PRIM_TRI_STRIP = 0x0040, + _DRM_R128_PRIM_TRI_TYPE2 = 0x0080 +} drm_r128_prim_t; + +typedef struct drm_r128_vertex { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int send_count; /* Number of buffers to send */ + int *send_indices; /* List of handles to buffers */ + int *send_sizes; /* Lengths of data to send */ + drm_r128_prim_t prim; /* Primitive type */ + int request_count; /* Number of buffers requested */ + int *request_indices; /* Buffer information */ + int *request_sizes; + int granted_count; /* Number of buffers granted */ +} drm_r128_vertex_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (r128_sarea.h) + */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +typedef struct drm_tex_region { + unsigned char next, prev; + unsigned char in_use; + int age; +} drm_tex_region_t; + +typedef struct drm_r128_sarea { + drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + int tex_age[R128_NR_TEX_HEAPS]; + int ctx_owner; + int ring_write; +} drm_r128_sarea_t; + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.c new file mode 100644 index 000000000..45ade1def --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.c @@ -0,0 +1,737 @@ +/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- + * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#define EXPORT_SYMTAB +#include "drmP.h" +#include "r128_drv.h" +EXPORT_SYMBOL(r128_init); +EXPORT_SYMBOL(r128_cleanup); + +#define R128_NAME "r128" +#define R128_DESC "r128" +#define R128_DATE "20000422" +#define R128_MAJOR 0 +#define R128_MINOR 0 +#define R128_PATCHLEVEL 5 + +static drm_device_t r128_device; +drm_ctx_t r128_res_ctx; + +static struct file_operations r128_fops = { + open: r128_open, + flush: drm_flush, + release: r128_release, + ioctl: r128_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice r128_misc = { + minor: MISC_DYNAMIC_MINOR, + name: R128_NAME, + fops: &r128_fops, +}; + +static drm_ioctl_desc_t r128_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { r128_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { r128_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { r128_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { r128_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { r128_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { r128_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { r128_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { r128_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { r128_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { r128_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { r128_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { r128_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + +#ifdef DRM_AGP + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, +#endif + + [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)] = { r128_eng_flush, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_CCEIDL)] = { r128_cce_idle, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, +}; +#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +static char *r128 = NULL; + +MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas."); +MODULE_DESCRIPTION("r128"); +MODULE_PARM(r128, "s"); + +/* init_module is called when insmod is used to load the module */ + +int init_module(void) +{ + return r128_init(); +} + +/* cleanup_module is called when rmmod is used to unload the module */ + +void cleanup_module(void) +{ + r128_cleanup(); +} +#endif + +#ifndef MODULE +/* r128_setup is called by the kernel to parse command-line options passed + * via the boot-loader (e.g., LILO). It calls the insmod option routine, + * drm_parse_drm. + * + * This is not currently supported, since it requires changes to + * linux/init/main.c. */ + + +void __init r128_setup(char *str, int *ints) +{ + if (ints[0] != 0) { + DRM_ERROR("Illegal command line format, ignored\n"); + return; + } + drm_parse_options(str); +} +#endif + +static int r128_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + drm_dma_setup(dev); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); + + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + r128_res_ctx.handle=-1; + + DRM_DEBUG("\n"); + + /* The kernel's context could be created here, but is now created + in drm_dma_enqueue. This is more resource-efficient for + hardware that does not do DMA, but may mean that + drm_select_queue fails between the time the interrupt is + initialized and the time the queues are initialized. */ + + return 0; +} + + +static int r128_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + +#ifdef DRM_AGP + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until r128_cleanup is called. */ + for (entry = dev->agp->memory; entry; entry = nexte) { + nexte = entry->next; + if (entry->bound) drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + } + dev->agp->memory = NULL; + + if (dev->agp->acquired && drm_agp.release) + (*drm_agp.release)(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } +#endif + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area and mtrr information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef CONFIG_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + drm_ioremapfree(map->handle, map->size); + break; + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + break; + } + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + drm_dma_takedown(dev); + + dev->queue_count = 0; + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +/* r128_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +int r128_init(void) +{ + int retcode; + drm_device_t *dev = &r128_device; + + DRM_DEBUG("\n"); + + memset((void *)dev, 0, sizeof(*dev)); + dev->count_lock = SPIN_LOCK_UNLOCKED; + sema_init(&dev->struct_sem, 1); + +#ifdef MODULE + drm_parse_options(r128); +#endif + + if ((retcode = misc_register(&r128_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", R128_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, r128_misc.minor); + dev->name = R128_NAME; + + drm_mem_init(); + drm_proc_init(dev); + +#ifdef DRM_AGP + dev->agp = drm_agp_init(); + +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size*1024*1024, + MTRR_TYPE_WRCOMB, + 1); +#endif +#endif + + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&r128_misc); + r128_takedown(dev); + return retcode; + } + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + R128_NAME, + R128_MAJOR, + R128_MINOR, + R128_PATCHLEVEL, + R128_DATE, + r128_misc.minor); + + return 0; +} + +/* r128_cleanup is called via cleanup_module at module unload time. */ + +void r128_cleanup(void) +{ + drm_device_t *dev = &r128_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&r128_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + drm_ctxbitmap_cleanup(dev); + r128_takedown(dev); +#ifdef DRM_AGP + if (dev->agp) { + /* FIXME -- free other information, too */ + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif +} + +int r128_version(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_version_t version; + int len; + + copy_from_user_ret(&version, + (drm_version_t *)arg, + sizeof(version), + -EFAULT); + +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + copy_to_user_ret(name, value, len, -EFAULT); \ + } + + version.version_major = R128_MAJOR; + version.version_minor = R128_MINOR; + version.version_patchlevel = R128_PATCHLEVEL; + + DRM_COPY(version.name, R128_NAME); + DRM_COPY(version.date, R128_DATE); + DRM_COPY(version.desc, R128_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int r128_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &r128_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { + MOD_INC_USE_COUNT; + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return r128_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int r128_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return r128_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= R128_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &r128_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + retcode = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + retcode = -EACCES; + } else { + retcode = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + return retcode; +} + +int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; +#if DRM_DMA_HISTOGRAM + cycles_t start; + + dev->lck_start = start = get_cycles(); +#endif + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + +#if 0 + /* dev->queue_count == 0 right now for + r128. FIXME? */ + if (lock.context < 0 || lock.context >= dev->queue_count) + return -EINVAL; +#endif + + if (!ret) { +#if 0 + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) + != lock.context) { + long j = jiffies - dev->lock.lock_time; + + if (lock.context == r128_res_ctx.handle && + j >= 0 && j < DRM_LOCK_SLICE) { + /* Can't take lock if we just had it and + there is contention. */ + DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n", + lock.context, current->pid, j, + dev->lock.lock_time, jiffies); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + schedule_timeout(DRM_LOCK_SLICE-j); + DRM_DEBUG("jiffies=%d\n", jiffies); + } + } +#endif + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; +#if 1 + current->policy |= SCHED_YIELD; +#endif + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + +#if 0 + if (!ret && dev->last_context != lock.context && + lock.context != r128_res_ctx.handle && + dev->last_context != r128_res_ctx.handle) { + add_wait_queue(&dev->context_wait, &entry); + current->state = TASK_INTERRUPTIBLE; + /* PRE: dev->last_context != lock.context */ + r128_context_switch(dev, dev->last_context, lock.context); + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == lock.context + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + current->policy |= SCHED_YIELD; + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->context_wait, &entry); + if (signal_pending(current)) { + ret = -EINTR; + } else if (dev->last_context != lock.context) { + DRM_ERROR("Context mismatch: %d %d\n", + dev->last_context, lock.context); + } + } +#endif + + if (!ret) { + if (lock.flags & _DRM_LOCK_READY) { + /* Wait for space in DMA/FIFO */ + } + if (lock.flags & _DRM_LOCK_QUIESCENT) { + /* Make hardware quiescent */ +#if 0 + r128_quiescent(dev); +#endif + } + } + +#if 0 + DRM_ERROR("pid = %5d, old counter = %5ld\n", + current->pid, current->counter); +#endif + if (lock.context != r128_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY/4; + } +#if 0 + while (current->counter > 25) + current->counter >>= 1; /* decrease time slice */ + DRM_ERROR("pid = %5d, new counter = %5ld\n", + current->pid, current->counter); +#endif + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); +#endif + + return ret; +} + + +int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + /* FIXME: Try to send data to card here */ + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + +#if 0 + current->policy |= SCHED_YIELD; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1000); +#endif + + if (lock.context != r128_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY; + } +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10); +#endif + + return 0; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.h new file mode 100644 index 000000000..3b888c493 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/r128_drv.h @@ -0,0 +1,226 @@ +/* r128_drv.h -- Private header for r128 driver -*- linux-c -*- + * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#ifndef _R128_DRV_H_ +#define _R128_DRV_H_ + +typedef struct drm_r128_private { + int is_pci; + + int cce_mode; + int cce_fifo_size; + int cce_is_bm_mode; + int cce_secure; + + drm_r128_sarea_t *sarea_priv; + + __volatile__ u32 *ring_read_ptr; + + u32 *ring_start; + u32 *ring_end; + int ring_size; + int ring_sizel2qw; + int ring_entries; + + int submit_age; + + int usec_timeout; + + drm_map_t *sarea; + drm_map_t *fb; + drm_map_t *agp_ring; + drm_map_t *agp_read_ptr; + drm_map_t *agp_vertbufs; + drm_map_t *agp_indbufs; + drm_map_t *agp_textures; + drm_map_t *mmio; +} drm_r128_private_t; + +typedef struct drm_r128_buf_priv { + u32 age; +} drm_r128_buf_priv_t; + + /* r128_drv.c */ +extern int r128_init(void); +extern void r128_cleanup(void); +extern int r128_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_open(struct inode *inode, struct file *filp); +extern int r128_release(struct inode *inode, struct file *filp); +extern int r128_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_dma.c */ +extern int r128_init_cce(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_eng_reset(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_eng_flush(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_submit_pkt(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_cce_idle(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_vertex_buf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_bufs.c */ +extern int r128_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_context.c */ +extern int r128_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int r128_context_switch(drm_device_t *dev, int old, int new); +extern int r128_context_switch_complete(drm_device_t *dev, int new); + + +/* Register definitions, register access macros and drmAddMap constants + * for Rage 128 kernel driver. + */ + +#define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_ALL 0x00ff +# define R128_PC_BUSY (1 << 31) + +#define R128_CLOCK_CNTL_INDEX 0x0008 +#define R128_CLOCK_CNTL_DATA 0x000c +# define R128_PLL_WR_EN (1 << 7) + +#define R128_MCLK_CNTL 0x000f +# define R128_FORCE_GCP (1 << 16) +# define R128_FORCE_PIPE3D_CPP (1 << 17) + +#define R128_GEN_RESET_CNTL 0x00f0 +# define R128_SOFT_RESET_GUI (1 << 0) + +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) + + +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) + +#define R128_PM4_VC_FPU_SETUP 0x071c + +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) + +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) + +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + +#define R128_GUI_SCRATCH_REG0 0x15e0 +#define R128_GUI_SCRATCH_REG1 0x15e4 +#define R128_GUI_SCRATCH_REG2 0x15e8 +#define R128_GUI_SCRATCH_REG3 0x15ec +#define R128_GUI_SCRATCH_REG4 0x15f0 +#define R128_GUI_SCRATCH_REG5 0x15f4 + +#define R128_GUI_STAT 0x1740 +# define R128_GUI_FIFOCNT_MASK 0x0fff +# define R128_GUI_ACTIVE (1 << 31) + + +/* CCE command packets */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +# define R128_CCE_PACKET_MASK 0xC0000000 +# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +# define R128_CCE_PACKET0_REG_MASK 0x000007ff +# define R128_CCE_PACKET1_REG0_MASK 0x000007ff +# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + + +#define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */ + + +#define R128_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define R128_ADDR(reg) (R128_BASE(reg) + reg) + +#define R128_DEREF(reg) *(__volatile__ int *)R128_ADDR(reg) +#define R128_READ(reg) R128_DEREF(reg) +#define R128_WRITE(reg,val) do { R128_DEREF(reg) = val; } while (0) + +#define R128_DEREF8(reg) *(__volatile__ char *)R128_ADDR(reg) +#define R128_READ8(reg) R128_DEREF8(reg) +#define R128_WRITE8(reg,val) do { R128_DEREF8(reg) = val; } while (0) + +#define R128_WRITE_PLL(addr,val) \ +do { \ + R128_WRITE8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \ + R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \ +} while (0) + +extern int R128_READ_PLL(drm_device_t *dev, int addr); + +#define R128CCE0(p,r,n) ((p) | ((n) << 16) | ((r) >> 2)) +#define R128CCE1(p,r1,r2) ((p) | (((r2) >> 2) << 11) | ((r1) >> 2)) +#define R128CCE2(p) ((p)) +#define R128CCE3(p,n) ((p) | ((n) << 16)) + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c index 85470ac52..9c2cea56a 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c @@ -1,8 +1,7 @@ /* vm.c -- Memory mapping for DRM -*- linux-c -*- * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com - * Revised: Mon Feb 14 00:16:45 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -246,13 +245,26 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) /* Check for valid size. */ if (map->size != vma->vm_end - vma->vm_start) return -EINVAL; + if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { + vma->vm_flags &= VM_MAYWRITE; +#if defined(__i386__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; +#else + /* Ye gads this is ugly. With more thought + we could move this up higher and use + `protection_map' instead. */ + vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( + __pte(pgprot_val(vma->vm_page_prot))))); +#endif + } switch (map->type) { case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: + case _DRM_AGP: if (VM_OFFSET(vma) >= __pa(high_memory)) { #if defined(__i386__) - if (boot_cpu_data.x86 > 3) { + if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } @@ -264,6 +276,10 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," + " offset = 0x%lx\n", + map->type, + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: @@ -276,19 +292,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) return -EINVAL; /* This should never happen. */ } vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ - if (map->flags & _DRM_READ_ONLY) { -#if defined(__i386__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; -#else - /* Ye gads this is ugly. With more thought - we could move this up higher and use - `protection_map' instead. */ - vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( - __pte(pgprot_val(vma->vm_page_prot))))); -#endif - } - #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ /* In Linux 2.2.3 and above, this is handled in do_mmap() in mm/mmap.c. */ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c index 3b0f98acd..2e3c9b431 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c @@ -1,8 +1,7 @@ /* xf86drm.c -- User-level interface to DRM device * Created: Tue Jan 5 08:16:21 1999 by faith@precisioninsight.com - * Revised: Sun Feb 13 23:43:32 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,6 +23,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * + * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.10 2000/02/23 04:47:23 martin Exp $ * */ @@ -143,7 +144,7 @@ static int drm_open(const char *file) return -errno; } -/* drmAvailable looks for /proc/drm, and returns 1 if it is present. */ +/* drmAvailable looks for /proc/dri, and returns 1 if it is present. */ int drmAvailable(void) { @@ -217,6 +218,20 @@ static int drmOpenByName(const char *name) group = xf86ConfigDRI.group ? xf86ConfigDRI.group : DRM_DEV_GID; #endif +#if defined(XFree86Server) + if (!drmAvailable()) { + /* try to load the kernel module now */ + if (!xf86LoadKernelModule(name)) { + ErrorF("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; + } + } +#else + if (!drmAvailable()) + return -1; +#endif + if (!geteuid()) { dirmode = mode; if (dirmode & S_IRUSR) dirmode |= S_IXUSR; @@ -418,7 +433,8 @@ int drmAddMap(int fd, return 0; } -int drmAddBufs(int fd, int count, int size, int flags) +int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) { drm_buf_desc_t request; @@ -427,6 +443,8 @@ int drmAddBufs(int fd, int count, int size, int flags) request.low_mark = 0; request.high_mark = 0; request.flags = flags; + request.agp_start = agp_offset; + if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno; return request.count; } @@ -744,6 +762,143 @@ int drmDestroyDrawable(int fd, drmDrawable handle) return 0; } +int drmAgpAcquire(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; + return 0; +} + +int drmAgpRelease(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; + return 0; +} + +int drmAgpEnable(int fd, unsigned long mode) +{ + drm_agp_mode_t m; + + m.mode = mode; + if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno; + return 0; +} + +int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, unsigned long *handle) +{ + drm_agp_buffer_t b; + *handle = 0; + b.size = size; + b.handle = 0; + b.type = type; + if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno; + if (address != 0UL) *address = b.physical; + *handle = b.handle; + return 0; +} + +int drmAgpFree(int fd, unsigned long handle) +{ + drm_agp_buffer_t b; + + b.size = 0; + b.handle = handle; + if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno; + return 0; +} + +int drmAgpBind(int fd, unsigned long handle, unsigned long offset) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = offset; + if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno; + return 0; +} + +int drmAgpUnbind(int fd, unsigned long handle) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = 0; + if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno; + return 0; +} + +int drmAgpVersionMajor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_major; +} + +int drmAgpVersionMinor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_minor; +} + +unsigned long drmAgpGetMode(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.mode; +} + +unsigned long drmAgpBase(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_base; +} + +unsigned long drmAgpSize(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_size; +} + +unsigned long drmAgpMemoryUsed(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_used; +} + +unsigned long drmAgpMemoryAvail(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_allowed; +} + +unsigned int drmAgpVendorId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_vendor; +} + +unsigned int drmAgpDeviceId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_device; +} + int drmError(int err, const char *label) { switch (err) { diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmI810.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmI810.c new file mode 100644 index 000000000..b2489eeed --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmI810.c @@ -0,0 +1,87 @@ +#ifdef XFree86Server +# include "xf86.h" +# include "xf86_OSproc.h" +# include "xf86_ansic.h" +# include "xf86Priv.h" +# define _DRM_MALLOC xalloc +# define _DRM_FREE xfree +# ifndef XFree86LOADER +# include <sys/stat.h> +# include <sys/mman.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <string.h> +# include <ctype.h> +# include <fcntl.h> +# include <errno.h> +# include <signal.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <sys/mman.h> +# include <sys/time.h> +# ifdef DRM_USE_MALLOC +# define _DRM_MALLOC malloc +# define _DRM_FREE free +extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); +extern int xf86RemoveSIGIOHandler(int fd); +# else +# include <Xlibint.h> +# define _DRM_MALLOC Xmalloc +# define _DRM_FREE Xfree +# endif +#endif + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include <sys/sysmacros.h> /* for makedev() */ +#include "xf86drm.h" +#include "xf86drmI810.h" +#include "drm.h" + +Bool drmI810CleanupDma(int driSubFD) +{ + drm_i810_init_t init; + + memset(&init, 0, sizeof(drm_i810_init_t)); + init.func = I810_CLEANUP_DMA; + + if(ioctl(driSubFD, DRM_IOCTL_I810_INIT, &init)) { + return FALSE; + } + + return TRUE; +} + +Bool drmI810InitDma(int driSubFD, drmI810Init *info) +{ + drm_i810_init_t init; + + memset(&init, 0, sizeof(drm_i810_init_t)); + + init.func = I810_INIT_DMA; + init.ring_map_idx = info->ring_map_idx; + init.buffer_map_idx = info->buffer_map_idx; + init.ring_start = info->start; + init.ring_end = info->end; + init.ring_size = info->size; + init.sarea_priv_offset = info->sarea_off; + init.front_offset = info->front_offset; + init.back_offset = info->back_offset; + init.depth_offset = info->depth_offset; + init.w = info->w; + init.h = info->h; + init.pitch = info->pitch; + init.pitch_bits = info->pitch_bits; + + if(ioctl(driSubFD, DRM_IOCTL_I810_INIT, &init)) { + return FALSE; + } + return TRUE; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmR128.c b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmR128.c new file mode 100644 index 000000000..99f267f3d --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmR128.c @@ -0,0 +1,199 @@ +/* xf86drmR128.c -- User-level interface to Rage 128 DRM device + * Created: Sun Apr 9 18:13:54 2000 by kevin@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#ifdef XFree86Server +# include "xf86.h" +# include "xf86_OSproc.h" +# include "xf86_ansic.h" +# include "xf86Priv.h" +# define _DRM_MALLOC xalloc +# define _DRM_FREE xfree +# ifndef XFree86LOADER +# include <sys/stat.h> +# include <sys/mman.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <string.h> +# include <ctype.h> +# include <fcntl.h> +# include <errno.h> +# include <signal.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <sys/mman.h> +# include <sys/time.h> +# ifdef DRM_USE_MALLOC +# define _DRM_MALLOC malloc +# define _DRM_FREE free +extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); +extern int xf86RemoveSIGIOHandler(int fd); +# else +# include <Xlibint.h> +# define _DRM_MALLOC Xmalloc +# define _DRM_FREE Xfree +# endif +#endif + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include <sys/sysmacros.h> /* for makedev() */ +#include "xf86drm.h" +#include "xf86drmR128.h" +#include "drm.h" + +int drmR128InitCCE(int fd, drmR128Init *info) +{ + drm_r128_init_t init; + + memset(&init, 0, sizeof(drm_r128_init_t)); + + init.func = R128_INIT_CCE; + init.sarea_priv_offset = info->sarea_priv_offset; + init.is_pci = info->is_pci; + init.cce_mode = info->cce_mode; + init.cce_fifo_size = info->cce_fifo_size; + init.cce_secure = info->cce_secure; + init.ring_size = info->ring_size; + init.usec_timeout = info->usec_timeout; + + init.fb_offset = info->fb_offset; + init.agp_ring_offset = info->agp_ring_offset; + init.agp_read_ptr_offset = info->agp_read_ptr_offset; + init.agp_vertbufs_offset = info->agp_vertbufs_offset; + init.agp_indbufs_offset = info->agp_indbufs_offset; + init.agp_textures_offset = info->agp_textures_offset; + init.mmio_offset = info->mmio_offset; + + if (ioctl(fd, DRM_IOCTL_R128_INIT, &init)) return -errno; + + return 0; +} + +int drmR128CleanupCCE(int fd) +{ + drm_r128_init_t init; + + memset(&init, 0, sizeof(drm_r128_init_t)); + + init.func = R128_CLEANUP_CCE; + + if (ioctl(fd, DRM_IOCTL_R128_INIT, &init)) return -errno; + + return 0; +} + +int drmR128EngineReset(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_RESET, NULL)) return -errno; + + return 0; +} + +int drmR128EngineFlush(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_FLUSH, NULL)) return -errno; + + return 0; +} + +int drmR128CCEWaitForIdle(int fd) +{ + if (ioctl(fd, DRM_IOCTL_R128_CCEIDL, NULL)) return -errno; + + return 0; +} + +int drmR128SubmitPackets(int fd, CARD32 *buffer, int *count, int flags) +{ + drm_r128_packet_t packet; + int ret; + + memset(&packet, 0, sizeof(drm_r128_packet_t)); + + packet.count = *count; + packet.flags = flags; + + while (packet.count > 0) { + packet.buffer = buffer + (*count - packet.count); + ret = ioctl(fd, DRM_IOCTL_R128_PACKET, &packet); + if (ret < 0 && ret != -EAGAIN) { + *count = packet.count; + return -errno; + } + } + + *count = 0; + return 0; +} + +int drmR128GetVertexBuffers(int fd, int count, int *indices, int *sizes) +{ + drm_r128_vertex_t v; + + v.send_count = 0; + v.send_indices = NULL; + v.send_sizes = NULL; + v.prim = DRM_R128_PRIM_NONE; + v.request_count = count; + v.request_indices = indices; + v.request_sizes = sizes; + v.granted_count = 0; + + if (ioctl(fd, DRM_IOCTL_R128_VERTEX, &v)) return -errno; + + return v.granted_count; +} + +int drmR128FlushVertexBuffers(int fd, int count, int *indices, + int *sizes, drmR128PrimType prim) +{ + drm_r128_vertex_t v; + + v.send_count = count; + v.send_indices = indices; + v.send_sizes = sizes; + v.prim = prim; + v.request_count = 0; + v.request_indices = NULL; + v.request_sizes = NULL; + v.granted_count = 0; + + if (ioctl(fd, DRM_IOCTL_R128_VERTEX, &v) < 0) return -errno; + + return 0; +} diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/drm.h b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/drm.h index 3af5d5b1e..c63d0f637 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/drm.h @@ -1,8 +1,7 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Mon Feb 14 00:15:23 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -71,9 +70,10 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; -/* Seperate include files for the i810/mga specific structures */ +/* Seperate include files for the i810/mga/r128 specific structures */ #include "mga_drm.h" #include "i810_drm.h" +#include "r128_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -341,12 +341,23 @@ typedef struct drm_agp_info { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) #define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) /* I810 specific ioctls */ #define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) #define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) #define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) #define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOW( 0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) + +/* Rage 128 specific ioctls */ +#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) +#define DRM_IOCTL_R128_RESET DRM_IO( 0x41) +#define DRM_IOCTL_R128_FLUSH DRM_IO( 0x42) +#define DRM_IOCTL_R128_CCEIDL DRM_IO( 0x43) +#define DRM_IOCTL_R128_PACKET DRM_IOW( 0x44, drm_r128_packet_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x45, drm_r128_vertex_t) #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h b/xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h index 61287e3e2..372ba595e 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h @@ -1,8 +1,7 @@ /* xf86drm.h -- OS-independent header for DRM user-level library interface * Created: Tue Jan 5 08:17:23 1999 by faith@precisioninsight.com - * Revised: Sun Feb 13 23:46:21 2000 by kevin@precisioninsight.com * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,6 +23,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * + * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h,v 1.7 2000/02/23 04:47:21 martin Exp $ * */ @@ -65,7 +66,8 @@ typedef struct _drmVersion { typedef enum { DRM_FRAME_BUFFER = 0, /* WC, no caching, no core dump */ DRM_REGISTERS = 1, /* no caching, no core dump */ - DRM_SHM = 2 /* shared, cached */ + DRM_SHM = 2, /* shared, cached */ + DRM_AGP = 3 /* AGP/GART */ } drmMapType; typedef enum { @@ -95,6 +97,11 @@ typedef enum { /* These values *MUST* match drm.h */ } drmDMAFlags; typedef enum { + DRM_PAGE_ALIGN = 0x01, + DRM_AGP_BUFFER = 0x02 +} drmBufDescFlags; + +typedef enum { DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */ DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */ DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */ @@ -196,7 +203,7 @@ typedef struct { unsigned int a[100]; } __drm_dummy_lock_t; #endif #ifndef DRM_CAS -#define DRM_CAS(lock,old,new,ret) /* FAST LOCK FAILS */ +#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */ #endif #define DRM_LIGHT_LOCK(fd,lock,context) \ @@ -291,7 +298,9 @@ extern int drmAddMap(int fd, drmMapType type, drmMapFlags flags, drmHandlePtr handle); -extern int drmAddBufs(int fd, int count, int size, int flags); +extern int drmAddBufs(int fd, int count, int size, + drmBufDescFlags flags, + int agp_offset); extern int drmMarkBufs(int fd, double low, double high); extern int drmCreateContext(int fd, drmContextPtr handle); extern int drmSetContextFlags(int fd, drmContext context, @@ -332,6 +341,29 @@ extern int drmGetLock(int fd, extern int drmUnlock(int fd, drmContext context); extern int drmFinish(int fd, int context, drmLockFlags flags); +/* AGP/GART support: X server (root) only */ +extern int drmAgpAcquire(int fd); +extern int drmAgpRelease(int fd); +extern int drmAgpEnable(int fd, unsigned long mode); +extern int drmAgpAlloc(int fd, unsigned long size, + unsigned long type, unsigned long *address, + unsigned long *handle); +extern int drmAgpFree(int fd, unsigned long handle); +extern int drmAgpBind(int fd, unsigned long handle, + unsigned long offset); +extern int drmAgpUnbind(int fd, unsigned long handle); + +/* AGP/GART info: authenticated client and/or X */ +extern int drmAgpVersionMajor(int fd); +extern int drmAgpVersionMinor(int fd); +extern unsigned long drmAgpGetMode(int fd); +extern unsigned long drmAgpBase(int fd); /* Physical location */ +extern unsigned long drmAgpSize(int fd); /* Bytes */ +extern unsigned long drmAgpMemoryUsed(int fd); +extern unsigned long drmAgpMemoryAvail(int fd); +extern unsigned int drmAgpVendorId(int fd); +extern unsigned int drmAgpDeviceId(int fd); + /* Support routines */ extern int drmError(int err, const char *label); extern void *drmMalloc(int size); diff --git a/xc/programs/Xserver/hw/xfree86/os-support/xf86drmI810.h b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmI810.h new file mode 100644 index 000000000..6c11b7a10 --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmI810.h @@ -0,0 +1,46 @@ + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (i810_drm.h) + */ + +#ifndef _XF86DRI_I810_H_ +#define _XF86DRI_I810_H_ + +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ +#define I810_USE_BATCH 1 + +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER) +#define I810_DMA_BUF_NR 256 + +#define I810_NR_SAREA_CLIPRECTS 8 + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define I810_NR_TEX_REGIONS 64 +#define I810_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +typedef struct _drmI810Init { + unsigned int start; + unsigned int end; + unsigned int size; + int ring_map_idx; + int buffer_map_idx; + int sarea_off; + + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; +} drmI810Init; + + +Bool drmI810CleanupDma(int driSubFD); +Bool drmI810InitDma(int driSubFD, drmI810Init *info ); + +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/xf86drmMga.h b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmMga.h new file mode 100644 index 000000000..3b0e4a6fc --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmMga.h @@ -0,0 +1,147 @@ + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (mga_drm.h) + */ + +#ifndef _XF86DRI_MGA_H_ +#define _XF86DRI_MGA_H_ +#ifndef _MGA_DEFINES_ +#define _MGA_DEFINES_ +#define MGA_F 0x1 /* fog */ +#define MGA_A 0x2 /* alpha */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + +#define MGA_WARP_TGZ 0 +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZAF (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) + +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_G200_PIPES 8 /* no multitex */ + +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES + +#define MGA_CARD_TYPE_G200 1 +#define MGA_CARD_TYPE_G400 2 +#define MGA_FRONT 0x1 +#define MGA_BACK 0x2 +#define MGA_DEPTH 0x4 + +/* 3d state excluding texture units: + */ +#define MGA_CTXREG_DSTORG 0 /* validated */ +#define MGA_CTXREG_MACCESS 1 +#define MGA_CTXREG_PLNWT 2 +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTXREG_FCOL 9 +#define MGA_CTX_SETUP_SIZE 10 + +/* 2d state + */ +#define MGA_2DREG_PITCH 0 +#define MGA_2D_SETUP_SIZE 1 + +/* Each texture unit has a state: + */ +#define MGA_TEXREG_CTL 0 +#define MGA_TEXREG_CTL2 1 +#define MGA_TEXREG_FILTER 2 +#define MGA_TEXREG_BORDERCOL 3 +#define MGA_TEXREG_ORG 4 /* validated */ +#define MGA_TEXREG_ORG1 5 +#define MGA_TEXREG_ORG2 6 +#define MGA_TEXREG_ORG3 7 +#define MGA_TEXREG_ORG4 8 +#define MGA_TEXREG_WIDTH 9 +#define MGA_TEXREG_HEIGHT 10 +#define MGA_TEX_SETUP_SIZE 11 + +/* What needs to be changed for the current vertex dma buffer? + */ +#define MGA_UPLOAD_CTX 0x1 +#define MGA_UPLOAD_TEX0 0x2 +#define MGA_UPLOAD_TEX1 0x4 +#define MGA_UPLOAD_PIPE 0x8 +#define MGA_UPLOAD_TEX0IMAGE 0x10 +#define MGA_UPLOAD_TEX1IMAGE 0x20 +#define MGA_UPLOAD_2D 0x40 +#define MGA_WAIT_AGE 0x80 /* handled client-side */ +#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ +#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock + quiescent */ + +/* 32 buffers of 64k each, total 1 meg. + */ +#define MGA_DMA_BUF_ORDER 16 +#define MGA_DMA_BUF_SZ (1<<MGA_DMA_BUF_ORDER) +#define MGA_DMA_BUF_NR 31 + +/* Keep these small for testing. + */ +#define MGA_NR_SAREA_CLIPRECTS 8 + +/* 2 heaps (1 for card, 1 for agp), each divided into upto 128 + * regions, subject to a minimum region size of (1<<16) == 64k. + * + * Clients may subdivide regions internally, but when sharing between + * clients, the region size is the minimum granularity. + */ + +#define MGA_CARD_HEAP 0 +#define MGA_AGP_HEAP 1 +#define MGA_NR_TEX_HEAPS 2 +#define MGA_NR_TEX_REGIONS 16 +#define MGA_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +typedef struct _drmMgaWarpIndex { + int installed; + unsigned long phys_addr; + int size; +} drmMgaWarpIndex; + +typedef struct _drmMgaInit { + int reserved_map_agpstart; + int reserved_map_idx; + int buffer_map_idx; + int sarea_priv_offset; + int primary_size; + int warp_ucode_size; + unsigned int frontOffset; + unsigned int backOffset; + unsigned int depthOffset; + unsigned int textureOffset; + unsigned int textureSize; + unsigned int agpTextureSize; + unsigned int agpTextureOffset; + unsigned int cpp; + unsigned int stride; + int sgram; + int chipset; + drmMgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; + unsigned int mAccess; +} drmMgaInit; + + +Bool drmMgaCleanupDma(int driSubFD); +Bool drmMgaLockUpdate(int driSubFD, drmLockFlags flags); +Bool drmMgaInitDma(int driSubFD, drmMgaInit *info); +#endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/xf86drmR128.h b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmR128.h new file mode 100644 index 000000000..46898a53c --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/os-support/xf86drmR128.h @@ -0,0 +1,80 @@ +/* xf86drm.h -- OS-independent header for DRM user-level library interface + * Created: Sun Apr 9 18:16:28 2000 by kevin@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Kevin E. Martin <kevin@precisioninsight.com> + * + * $XFree86$ + * + */ + +#ifndef _XF86DRI_R128_H_ +#define _XF86DRI_R128_H_ + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (r128_drm.h) + */ + +typedef struct _drmR128Init { + int sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_fifo_size; + int cce_secure; + int ring_size; + int usec_timeout; + + int fb_offset; + int agp_ring_offset; + int agp_read_ptr_offset; + int agp_vertbufs_offset; + int agp_indbufs_offset; + int agp_textures_offset; + int mmio_offset; +} drmR128Init; + +typedef enum { + DRM_R128_PRIM_NONE = 0x0001, + DRM_R128_PRIM_POINT = 0x0002, + DRM_R128_PRIM_LINE = 0x0004, + DRM_R128_PRIM_POLY_LINE = 0x0008, + DRM_R128_PRIM_TRI_LIST = 0x0010, + DRM_R128_PRIM_TRI_FAN = 0x0020, + DRM_R128_PRIM_TRI_STRIP = 0x0040, + DRM_R128_PRIM_TRI_TYPE2 = 0x0080 +} drmR128PrimType; + + +extern int drmR128InitCCE(int fd, drmR128Init *info); +extern int drmR128CleanupCCE(int fd); +extern int drmR128EngineReset(int fd); +extern int drmR128EngineFlush(int fd); +extern int drmR128CCEWaitForIdle(int fd); +extern int drmR128SubmitPackets(int fd, CARD32 *buffer, int *count, int flags); +extern int drmR128GetVertexBuffers(int fd, int count, int *indices, + int *sizes); +extern int drmR128FlushVertexBuffers(int fd, int count, int *indices, + int *sizes, drmR128PrimType prim); + +#endif |