NOTE: This page is outdated and is only retained for historical purposes. Suspend with KMS has been implemented and working for all cards exept for TNT2.
Latest news:
10.10.2009 posted by benkai
Ben Skeggs has given a great update on the status of Nouveau including an update on Suspend/Resume:
Suspend/Resume
Yes, that's right, Nouveau finally supports suspend/resume. In theory the support is there for all chipsets. In the very least, every chipset I own (at least one from each family, and 5 G80-class cards) can suspend/resume reliably except for a TNT2 that has other issues.. This support is only available when kernel modesetting is switched on, so that's even more reason to use it!
The following status only applies to TNT2:
1. Intro / FAQ
Q: Is suspend working with nouveau?
A: In unpatched nouveau, only if you use Option "ShadowFB" "on" in your xorg.conf, but this only works for s2disk and disables all acceleration for 2D and 3D and disables Xv.
Q: (Follow-up) Is it possible to get rid of Option "ShadowFB" "on" for nouveau suspend to have Xv and EXA working?
A: Yes, Stuart Bennett (malc0) has a patch for nv0x-nv4x: http://people.freedesktop.org/~stuart/nv0x-nv3x_suspend/ (also install the current drm repro)
- Q: Do malc0's patches also work with running 3D applications?
- A: Maybe, please test and report!
- Q: Do malc0's patches also work with running 3D applications?
Q: (Follow-up) Is there a way to make this work with s2ram?
- A: Yes, but none is working for all cards yet, so it requires some experimentation and work.
a) You can try to add a call to vbetool post to your resume script to light up the monitor after s2ram. Similarily, you can try to add acpi_sleep=s3_bios,s3_mode to your kernel command line.
- Note, this only works on Intel machines as it requres the execution of Intel machine code.
You call nouveau's BIOS-parsing card init routine when your X server switches to the X terminal: http://pastebin.com/m4287d7bf
- Note: You have to restore the backlight registers NV_PBUS_DEBUG_DUALHEAD_CTL and NV_CRTC_GPIO_EXT using radeontool (the version for nouveau) to get backlight back. On PPC, you have to set the card to big endian mode before running nouveau's BIOS parser to init the card. Ask moondrake in IRC for further information.
Matthew Garrett (mjg59) and Stuart Bennett (malc0) managed to run nouveau'S BIOS parser in the kernel (see http://mjg59.livejournal.com/91888.html ) together with nv but it is not integrated with nouveau yet, causes lockups with nouveau and only works for certain older cards (like nv44). For more info, look at the section on cold-booting the card.
- Comment: Nouveau BIOS-parsing card init (both methods, 1 and 2) does not restore text mode.
2. Outlook
Ben Skeggs has been hired by RedHat and so he can work on the features which are important for RedHat and distributions in general, like KMS and suspend/resume which seems to be fully done now. In any case, you can come to the nouveau IRC channel, report any issueas and ask if you could help.
3. Possibilities for suspending and resuming the card
3.1. s2ram
Working suspend2ram requires ability to cold-boot (also called POSTing - "Power-On Self-Test") the card. This is very card-specifc, and may work on some hardware with some method, or not. Currently, there are the following ways how the card can be posted. This does much more than just turning on the backlight (eg. like xset dpms). Fore example it needs to init the nvidia ASIC, upload the firmware into it and boot it.
3.1.1. Cold-booting the card using x86 BIOS routines
The VESA BIOS Extensions (VBE) provide a way to POST the card even after boot with cards whose VESA BIOS is working after boot. For many (nmost?) nvidia cards, it's not, but the BIOS of G8x cards (nv50) cards seems to work.
- There are two ways to use the VESA BIOS to post the card:
- In the kernel: Controlled thru the boot parameter "acpi_sleep=[s3_bios,s3_mode] and thru /proc/sys/kernel/acpi_video_flags (can be set by the s2ram tool) the kernel will, on resume, POST the card and/or set the VBE mode which it saved before suspending. If the kernel is told to also restore the test mode (s3_bios,s3_mode), it will also restore the text mode.
- From Linux user space thru vbetool post. This does not restore the text mode, it only cold-boots the card. The now-implemented nv50 kernel modesetting is used to restore the text mode.
3.1.2. Cold-booting the card by interpreting the init scripts in the Video BIOS
This depends on nouveau's BIOS parser to correctly interpret the reverse-engineered init script of your Nvidia BIOS.
- There are two ways to cold-boot the card by interpreting the Nvidia BIOS tables:
In xf86-video-nouveau/src/nv_bios.c, change pNv->VBIOS.execute = false to true.
A copy of it is comverted to run in the kernel and available at http://mjg59.livejournal.com/91888.html
These BIOS parsers do not set or restore a text mode after cold-booting the card, and they only work for nv4x cards and older. (For nv5x cards the VBE POST can be used.)
3.2. s2disk
For s2disk, the machine is ultimatively turned off completely and all power can be removed. The resume process is preceeded by a normal system boot thru the BIOS, so the card is initialized by the VGA BIOS in this case, so we do not need to have cold-booting the card working.
4. Support for suspend in other drivers
- The blob has support for suspend2disk and suspend2ram, but on some newer cards (some G80 cards) it fails to resume from disk.
- The nv driver has suspend2disk working (at least with g80 cards). Switching to a text console before suspend (like suspend scripts usually do) is required tough. It re-initializes the g80 hardware in each EnterVT when switching back to X.
5. About Option "ShadowFB" "on"
"ShadowFB" disables Xv, EXA and hardware-accelerated RENDER as well as hardware 3D. If you only need 2D graphics and your system is fast, ShadowFB is likely also fast, but you have to switch to the text console before suspending.
6. Possible tools for reverse-engineering
Hopefully, MmioTrace works during suspending and resume. mmiotrace does not provide much symboic information on nv5x cards yet.
7. Low-level intro
Note: Below, you may Nvidia-specific terms which you may not know yet. Read HonzaHavlicek to understand what they mean.
Nvidia cards are composed of several separate units: PMC, PTIMER, PFB, PGRAPH and PFIFO. Nouveaus's GPU initialisation code in nouveau.ko is called during X server startup thru an ioctl which is issued during DRI initialisation. nouveau.ko skips this step if nouveau.ko's internal status indicates that the GPU is already initialized.
Even the oldest cards supported by nouveau (NV04 = TNT2) have a GPU unit which has support for multi-tasking like a full-blown CPU and they even appear to have other CPU-like features like memory protection so that one "GPU process" cannot mess up the state of other "GPU processes", and Nouveau does a context switch between two such GPU processes even as part of the X startup. For 2D and 3D acceleration in parallel, these context switches have to be working.
All the GPU processes which were set up before suspending need to be saved and have to be restored on resume - after the various parts of the GPU are initialized. Contexts of these "GPU processes" live in differnt parts of the GPU, one part of these GPU contexts lives in the actual drawing engine (PGRAPH) while one part lives in the part which feeds the drawing engine with the commands for drawing (the PFIFO).
7.1. Low-Level Card initialisation in nouveau.ko
The initialisation routines for the nvidia chip components differ from chip generation to chip generation, so the 1st step which nouveau.ko does is checking which chip generation the card uses. Depending on the generation, the pointers to the card-specific functions are set to the card-specific functions for the detected chip generation. When the GPU initialisation is finally called, the card-specific initialisation functions for the various initialsation stages are executed. First, the initialisaiton functions for rather low-level units are called. The first one is the PMC. It seems to be someting like a power switch for the other units, at least it seems to be used by the initialisation functions of the other units to power-cycle the respective unit before it is initialized. At least on NV04, init of PMC, PTIMER, PFB and PGRAPH are trivial. PFIFO init is where things get more involved. PFIFO needs to know the locations of several parts of the cards "instance memory"(a special memory region in VRAM, reserved for the internal GPU status and commands, size is 512 KiB or 1MiB, depending on the card): RAMHT (hash tables), RAMFC (FIFO context) and RAMRO (FIFO runout table). This information is configured and written to the FIFO in fifo_instance_mem_init() and that part is still trivial.
All drawing commands are sent to the GPU inside a "channel" (someting like a process for a CPU). A channel is composed of it's FIFO context, it's PGRAPH context, as well as allocated GPU objects and DMA objects.
DMA and Interrupt setup are the final stages of the GPU initialisation routine in nouveau.ko. Current status is that I can run the init routines of PMC, PTIMER and PFB during EnterVT when switching from console text mode back to graphics mode on NV04 and have EXA still working, to add make GPRAPH init I have to call the graph_save_context and graph_load_context routines around graph_init(), but for PFIFO init, it gets more tricky, see below, and for that, we may need some mmiotraces to know what to do to get the combination of PGRAPH and PFIFO init work.
Off-Topic: Regarding saving power): Depending on wether the PMC really can really power-down all the other units of the GPU, the PMC and the suspend code in general could used to save power (= gain of battery time) using nouveau (in addition to reducing the clock speed with nvclock) when no drawing is done thru the GPU or when all drawing is done directly by the CPU like when ShadowFB is enabled. When nothing is drawn for some time, we could already (with current code) test wether we can turn off PTIMER, PFB and PGRAPH and turn them on again quickly triggered by trapping writes the the user-space command submission buffer. When suspend is working, we could turn off most chip compenents to save power and restore their status when drawing starts again.
7.1.1. Examples of what we need to do on Nvidia chip generations
- All generations: Tell the card the location of RAMHT, RAMRO and RAMFC thru writes to the registers NV03_PFIFO_RAMHT, NV03_PFIFO_RAMRO, NV03_PFIFO_RAMFC/NV40_PFIFO_RAMFC by calling nouveau_fifo_instmem_configure() from nouveau_fifo_init() inside the nouveau drm kernel module.
- NV40 and newer: Write the Voodoo into the card
- NV50 and newer (and maybe als older ones like NV28): Write the CTXVals into the card
malc0's suspend patch does this by calling mc.init(), timer.init(), fb.init(), graph.init() and fifo.init(). Afterwards, he restores the RAMIN area.
8. Channel data objects
What should we do with all the gpu data objects in the channels?
When a channel is allocated and used, lots of gpu data objects are allocated in VRAM. Data structures are complex: Each channel has a fifo context which has a pushbuf attached which has a number of gpu objechts (look at nouveau_fifo_alloc). FIFO alloc is started from user space, goes into the kernel and back to do remaining things in user space again.
malc0's patch saves and restore the whole RAMIN area instead. The space currently allocated to RAMIN by nouveau is 1MiB for >=NV40 and 512kib for all older cards. It would take less memory to save and restore RAMFC, RAMRO and then not the complete RAMIN heap but only the allocated GPU objects in it. For that, we'd have to traverse thru the list of allocated gpu_objects within the memory management of nouveau/drm and back up those.
In theory, it would be nice to allocate the RAMIN backup space in swappable memory (may have to be allocated by the user process?) and use copy_to/from_user for the transfer in order to not require a large continous chunk of memory (which may not be available if memory gets fragmented), but swapping would need to be running during suspend/resume for this to work.
9. Links
Patch for the DDX to dump the card's registers into the log: http://www.cse.iitk.ac.in/users/arunsr/gentoo/overlay/x11-drivers/xf86-video-nouveau/files/nouveau-ddx-dump-regs.diff
10. Obsolete progress reports from Spring 2008
BernhardKaindl: After adding save/restore of all PFIFO regs, I now even get a PGRAPH context switch interrupt (it's alive! it's alive!) after X starts sending commands thru the FIFO again, so that looks good. The bad news is that I get weird errors from the card afterwards... After seeing this this, I guess we should really take MMIO traces of the blob when it's suspending and resuming the card as there might be GPU state in registers and memory areas which might not even be used by nouevau so far as they might be very card-internal and only need to be touched to save and restore a complete GPU status. Another possibility would be that the the state which gets lost is in RAMIN - I think that I didn't touch RAMIN in this initial experiment, so I hoped it's not touched at alls, bit it might be that the FIFO initialisation also initiialses part of the RAMIN area for example possibly to RAMRO aread (FIFO runout area - nouveau does not know anyting about it, nouveau only allocates space for it), so saving the RAMIN area (which includes RAMRO and hopefully all the rest of the FIFO status) before re-initialising the GPU and restoring it afterwards would be a try. Ideally, we should be getting a mmiostrace of a suspend of the blob so we can really *see* what the blob is doing there. Now that I have understood some basics of the card, such mmiotrace should be able to tell me something.
BernhardKaindl: Tested new ioctl to initialize the GPU and added a call to it to EnterVT, so it's called whenever the VT is switched to the VT where X runs. This allows for quick testing of kernel code which is intented to save the current GPU status, re-inits the GPU and restores the saved GPU status. This seems to work with NV04 for the testing of re-initializing PMC, PTIMER, PFB and PGRAPH (not PFIFO) now. PMC, PTIMER and PFB init did't need any save/restore in my tests, but PGRATH needs save/restore. PGRAPH save/restore was trivial on NV04: Simply allocate a channel and call engine->graph.save_context() before PGRAPH init and engine->graph.restore_context() afterwards. After that nouveau was working after a LeaveVT/EnterVT (with PMC/PTIMER/PFB/GPRAPH init) cycle, yes!