103b705cfSriastradh/* -*- c-basic-offset: 4 -*- */ 203b705cfSriastradh/* 303b705cfSriastradh * Copyright © 2006 Intel Corporation 403b705cfSriastradh * 503b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 603b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 703b705cfSriastradh * to deal in the Software without restriction, including without limitation 803b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 903b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 1003b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1103b705cfSriastradh * 1203b705cfSriastradh * The above copyright notice and this permission notice (including the next 1303b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1403b705cfSriastradh * Software. 1503b705cfSriastradh * 1603b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1703b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1803b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1903b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2003b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2103b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2203b705cfSriastradh * SOFTWARE. 2303b705cfSriastradh * 2403b705cfSriastradh * Authors: 2503b705cfSriastradh * Eric Anholt <eric@anholt.net> 2603b705cfSriastradh * 2703b705cfSriastradh */ 2803b705cfSriastradh 2903b705cfSriastradh#ifdef HAVE_CONFIG_H 3003b705cfSriastradh#include "config.h" 3103b705cfSriastradh#endif 3203b705cfSriastradh 3303b705cfSriastradh#include <assert.h> 3403b705cfSriastradh#include <stdlib.h> 3503b705cfSriastradh#include <errno.h> 3603b705cfSriastradh 3742542f5fSchristos#include "xorg-server.h" 3803b705cfSriastradh#include "xf86.h" 3903b705cfSriastradh#include "intel.h" 4003b705cfSriastradh#include "i830_reg.h" 4103b705cfSriastradh#include "i915_drm.h" 4203b705cfSriastradh#include "i965_reg.h" 4303b705cfSriastradh 4413496ba1Ssnj#include "intel_uxa.h" 4503b705cfSriastradh 4603b705cfSriastradh#define DUMP_BATCHBUFFERS NULL // "/tmp/i915-batchbuffers.dump" 4703b705cfSriastradh 4803b705cfSriastradhstatic void intel_end_vertex(intel_screen_private *intel) 4903b705cfSriastradh{ 5003b705cfSriastradh if (intel->vertex_bo) { 5103b705cfSriastradh if (intel->vertex_used) { 5203b705cfSriastradh dri_bo_subdata(intel->vertex_bo, 0, intel->vertex_used*4, intel->vertex_ptr); 5303b705cfSriastradh intel->vertex_used = 0; 5403b705cfSriastradh } 5503b705cfSriastradh 5603b705cfSriastradh dri_bo_unreference(intel->vertex_bo); 5703b705cfSriastradh intel->vertex_bo = NULL; 5803b705cfSriastradh } 5903b705cfSriastradh 6003b705cfSriastradh intel->vertex_id = 0; 6103b705cfSriastradh} 6203b705cfSriastradh 6303b705cfSriastradhvoid intel_next_vertex(intel_screen_private *intel) 6403b705cfSriastradh{ 6503b705cfSriastradh intel_end_vertex(intel); 6603b705cfSriastradh 6703b705cfSriastradh intel->vertex_bo = 6803b705cfSriastradh dri_bo_alloc(intel->bufmgr, "vertex", sizeof (intel->vertex_ptr), 4096); 6903b705cfSriastradh} 7003b705cfSriastradh 7103b705cfSriastradhstatic dri_bo *bo_alloc(ScrnInfoPtr scrn) 7203b705cfSriastradh{ 7303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 7403b705cfSriastradh int size = 4 * 4096; 7503b705cfSriastradh /* The 865 has issues with larger-than-page-sized batch buffers. */ 7603b705cfSriastradh if (IS_I865G(intel)) 7703b705cfSriastradh size = 4096; 7803b705cfSriastradh return dri_bo_alloc(intel->bufmgr, "batch", size, 4096); 7903b705cfSriastradh} 8003b705cfSriastradh 8103b705cfSriastradhstatic void intel_next_batch(ScrnInfoPtr scrn, int mode) 8203b705cfSriastradh{ 8303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 8403b705cfSriastradh dri_bo *tmp; 8503b705cfSriastradh 8603b705cfSriastradh drm_intel_gem_bo_clear_relocs(intel->batch_bo, 0); 8703b705cfSriastradh 8803b705cfSriastradh tmp = intel->last_batch_bo[mode]; 8903b705cfSriastradh intel->last_batch_bo[mode] = intel->batch_bo; 9003b705cfSriastradh intel->batch_bo = tmp; 9103b705cfSriastradh 9203b705cfSriastradh intel->batch_used = 0; 9303b705cfSriastradh 9403b705cfSriastradh /* We don't know when another client has executed, so we have 9503b705cfSriastradh * to reinitialize our 3D state per batch. 9603b705cfSriastradh */ 9703b705cfSriastradh intel->last_3d = LAST_3D_OTHER; 9803b705cfSriastradh} 9903b705cfSriastradh 10003b705cfSriastradhvoid intel_batch_init(ScrnInfoPtr scrn) 10103b705cfSriastradh{ 10203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 10303b705cfSriastradh 10403b705cfSriastradh intel->batch_emit_start = 0; 10503b705cfSriastradh intel->batch_emitting = 0; 10603b705cfSriastradh intel->vertex_id = 0; 10703b705cfSriastradh 10803b705cfSriastradh intel->last_batch_bo[0] = bo_alloc(scrn); 10903b705cfSriastradh intel->last_batch_bo[1] = bo_alloc(scrn); 11003b705cfSriastradh 11103b705cfSriastradh intel->batch_bo = bo_alloc(scrn); 11203b705cfSriastradh intel->batch_used = 0; 11303b705cfSriastradh intel->last_3d = LAST_3D_OTHER; 11403b705cfSriastradh} 11503b705cfSriastradh 11603b705cfSriastradhvoid intel_batch_teardown(ScrnInfoPtr scrn) 11703b705cfSriastradh{ 11803b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 11903b705cfSriastradh int i; 12003b705cfSriastradh 12103b705cfSriastradh for (i = 0; i < ARRAY_SIZE(intel->last_batch_bo); i++) { 12203b705cfSriastradh if (intel->last_batch_bo[i] != NULL) { 12303b705cfSriastradh dri_bo_unreference(intel->last_batch_bo[i]); 12403b705cfSriastradh intel->last_batch_bo[i] = NULL; 12503b705cfSriastradh } 12603b705cfSriastradh } 12703b705cfSriastradh 12803b705cfSriastradh if (intel->batch_bo != NULL) { 12903b705cfSriastradh dri_bo_unreference(intel->batch_bo); 13003b705cfSriastradh intel->batch_bo = NULL; 13103b705cfSriastradh } 13203b705cfSriastradh 13303b705cfSriastradh if (intel->vertex_bo) { 13403b705cfSriastradh dri_bo_unreference(intel->vertex_bo); 13503b705cfSriastradh intel->vertex_bo = NULL; 13603b705cfSriastradh } 13703b705cfSriastradh 13803b705cfSriastradh while (!list_is_empty(&intel->batch_pixmaps)) 13903b705cfSriastradh list_del(intel->batch_pixmaps.next); 14003b705cfSriastradh} 14103b705cfSriastradh 14203b705cfSriastradhstatic void intel_batch_do_flush(ScrnInfoPtr scrn) 14303b705cfSriastradh{ 14403b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 14513496ba1Ssnj struct intel_uxa_pixmap *priv; 14603b705cfSriastradh 14703b705cfSriastradh list_for_each_entry(priv, &intel->batch_pixmaps, batch) 14803b705cfSriastradh priv->dirty = 0; 14903b705cfSriastradh} 15003b705cfSriastradh 15103b705cfSriastradhstatic void intel_emit_post_sync_nonzero_flush(ScrnInfoPtr scrn) 15203b705cfSriastradh{ 15303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 15403b705cfSriastradh 15503b705cfSriastradh /* keep this entire sequence of 3 PIPE_CONTROL cmds in one batch to 15603b705cfSriastradh * avoid upsetting the gpu. */ 15703b705cfSriastradh BEGIN_BATCH(3*4); 15803b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 15903b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_CS_STALL | 16003b705cfSriastradh BRW_PIPE_CONTROL_STALL_AT_SCOREBOARD); 16103b705cfSriastradh OUT_BATCH(0); /* address */ 16203b705cfSriastradh OUT_BATCH(0); /* write data */ 16303b705cfSriastradh 16403b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 16503b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WRITE_QWORD); 16603b705cfSriastradh OUT_RELOC(intel->wa_scratch_bo, 16703b705cfSriastradh I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0); 16803b705cfSriastradh OUT_BATCH(0); /* write data */ 16903b705cfSriastradh 17003b705cfSriastradh /* now finally the _real flush */ 17103b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 17203b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 17303b705cfSriastradh BRW_PIPE_CONTROL_TC_FLUSH | 17403b705cfSriastradh BRW_PIPE_CONTROL_NOWRITE); 17503b705cfSriastradh OUT_BATCH(0); /* write address */ 17603b705cfSriastradh OUT_BATCH(0); /* write data */ 17703b705cfSriastradh ADVANCE_BATCH(); 17803b705cfSriastradh} 17903b705cfSriastradh 18003b705cfSriastradhvoid intel_batch_emit_flush(ScrnInfoPtr scrn) 18103b705cfSriastradh{ 18203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 18303b705cfSriastradh int flags; 18403b705cfSriastradh 18503b705cfSriastradh assert (!intel->in_batch_atomic); 18603b705cfSriastradh 18703b705cfSriastradh /* Big hammer, look to the pipelined flushes in future. */ 18842542f5fSchristos if ((INTEL_INFO(intel)->gen >= 0100)) { 18942542f5fSchristos /* Only BLT supported */ 19042542f5fSchristos BEGIN_BATCH_BLT(4); 19142542f5fSchristos OUT_BATCH(MI_FLUSH_DW | 2); 19242542f5fSchristos OUT_BATCH(0); /* address low */ 19342542f5fSchristos OUT_BATCH(0); /* address high */ 19442542f5fSchristos OUT_BATCH(0); /* dword data */ 19542542f5fSchristos ADVANCE_BATCH(); 19642542f5fSchristos } else if ((INTEL_INFO(intel)->gen >= 060)) { 19703b705cfSriastradh if (intel->current_batch == BLT_BATCH) { 19803b705cfSriastradh BEGIN_BATCH_BLT(4); 19903b705cfSriastradh OUT_BATCH(MI_FLUSH_DW | 2); 20042542f5fSchristos OUT_BATCH(0); /* address */ 20142542f5fSchristos OUT_BATCH(0); /* qword low */ 20242542f5fSchristos OUT_BATCH(0); /* qword high */ 20303b705cfSriastradh ADVANCE_BATCH(); 20403b705cfSriastradh } else { 20503b705cfSriastradh if ((INTEL_INFO(intel)->gen == 060)) { 20603b705cfSriastradh /* HW-Workaround for Sandybdrige */ 20703b705cfSriastradh intel_emit_post_sync_nonzero_flush(scrn); 20803b705cfSriastradh } else { 20903b705cfSriastradh BEGIN_BATCH(4); 21003b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL | (4 - 2)); 21103b705cfSriastradh OUT_BATCH(BRW_PIPE_CONTROL_WC_FLUSH | 21203b705cfSriastradh BRW_PIPE_CONTROL_TC_FLUSH | 21303b705cfSriastradh BRW_PIPE_CONTROL_NOWRITE); 21403b705cfSriastradh OUT_BATCH(0); /* write address */ 21503b705cfSriastradh OUT_BATCH(0); /* write data */ 21603b705cfSriastradh ADVANCE_BATCH(); 21703b705cfSriastradh } 21803b705cfSriastradh } 21903b705cfSriastradh } else { 22003b705cfSriastradh flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 22103b705cfSriastradh if (INTEL_INFO(intel)->gen >= 040) 22203b705cfSriastradh flags = 0; 22303b705cfSriastradh 22403b705cfSriastradh BEGIN_BATCH(1); 22503b705cfSriastradh OUT_BATCH(MI_FLUSH | flags); 22603b705cfSriastradh ADVANCE_BATCH(); 22703b705cfSriastradh } 22803b705cfSriastradh intel_batch_do_flush(scrn); 22903b705cfSriastradh} 23003b705cfSriastradh 23103b705cfSriastradhvoid intel_batch_submit(ScrnInfoPtr scrn) 23203b705cfSriastradh{ 23303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 23403b705cfSriastradh int ret; 23503b705cfSriastradh 23603b705cfSriastradh assert (!intel->in_batch_atomic); 23703b705cfSriastradh 23803b705cfSriastradh if (intel->vertex_flush) 23903b705cfSriastradh intel->vertex_flush(intel); 24003b705cfSriastradh intel_end_vertex(intel); 24103b705cfSriastradh 24203b705cfSriastradh if (intel->batch_flush) 24303b705cfSriastradh intel->batch_flush(intel); 24403b705cfSriastradh 24503b705cfSriastradh if (intel->batch_used == 0) 24603b705cfSriastradh return; 24703b705cfSriastradh 248fe8aea9eSmrg if (intel->current_batch == I915_EXEC_BLT && 249fe8aea9eSmrg INTEL_INFO(intel)->gen >= 060) { 250fe8aea9eSmrg OUT_BATCH(MI_FLUSH_DW); 251fe8aea9eSmrg OUT_BATCH(0); 252fe8aea9eSmrg OUT_BATCH(0); 253fe8aea9eSmrg OUT_BATCH(0); 254fe8aea9eSmrg OUT_BATCH(MI_LOAD_REGISTER_IMM); 255fe8aea9eSmrg OUT_BATCH(BCS_SWCTRL); 256fe8aea9eSmrg OUT_BATCH((BCS_SWCTRL_DST_Y | BCS_SWCTRL_SRC_Y) << 16); 257fe8aea9eSmrg } 258fe8aea9eSmrg 25903b705cfSriastradh /* Mark the end of the batchbuffer. */ 26003b705cfSriastradh OUT_BATCH(MI_BATCH_BUFFER_END); 26103b705cfSriastradh /* Emit a padding dword if we aren't going to be quad-word aligned. */ 26203b705cfSriastradh if (intel->batch_used & 1) 26303b705cfSriastradh OUT_BATCH(MI_NOOP); 26403b705cfSriastradh 26503b705cfSriastradh if (DUMP_BATCHBUFFERS) { 26603b705cfSriastradh FILE *file = fopen(DUMP_BATCHBUFFERS, "a"); 26703b705cfSriastradh if (file) { 26803b705cfSriastradh fwrite (intel->batch_ptr, intel->batch_used*4, 1, file); 26903b705cfSriastradh fclose(file); 27003b705cfSriastradh } 27103b705cfSriastradh } 27203b705cfSriastradh 27303b705cfSriastradh ret = dri_bo_subdata(intel->batch_bo, 0, intel->batch_used*4, intel->batch_ptr); 27403b705cfSriastradh if (ret == 0) { 27503b705cfSriastradh ret = drm_intel_bo_mrb_exec(intel->batch_bo, 27603b705cfSriastradh intel->batch_used*4, 27703b705cfSriastradh NULL, 0, 0xffffffff, 27803b705cfSriastradh (HAS_BLT(intel) ? 27903b705cfSriastradh intel->current_batch: 28003b705cfSriastradh I915_EXEC_DEFAULT)); 28103b705cfSriastradh } 28203b705cfSriastradh 28303b705cfSriastradh if (ret != 0) { 28403b705cfSriastradh static int once; 28503b705cfSriastradh if (!once) { 28603b705cfSriastradh if (ret == -EIO) { 28703b705cfSriastradh /* The GPU has hung and unlikely to recover by this point. */ 28803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Detected a hung GPU, disabling acceleration.\n"); 28903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, "When reporting this, please include i915_error_state from debugfs and the full dmesg.\n"); 29003b705cfSriastradh } else { 29103b705cfSriastradh /* The driver is broken. */ 29203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_ERROR, 29303b705cfSriastradh "Failed to submit batch buffer, expect rendering corruption: %s.\n ", 29403b705cfSriastradh strerror(-ret)); 29503b705cfSriastradh } 29603b705cfSriastradh uxa_set_force_fallback(xf86ScrnToScreen(scrn), TRUE); 29703b705cfSriastradh intel->force_fallback = TRUE; 29803b705cfSriastradh once = 1; 29903b705cfSriastradh } 30003b705cfSriastradh } 30103b705cfSriastradh 30203b705cfSriastradh while (!list_is_empty(&intel->batch_pixmaps)) { 30313496ba1Ssnj struct intel_uxa_pixmap *entry; 30403b705cfSriastradh 30503b705cfSriastradh entry = list_first_entry(&intel->batch_pixmaps, 30613496ba1Ssnj struct intel_uxa_pixmap, 30703b705cfSriastradh batch); 30803b705cfSriastradh 30903b705cfSriastradh entry->busy = -1; 31003b705cfSriastradh entry->dirty = 0; 31103b705cfSriastradh list_del(&entry->batch); 31203b705cfSriastradh } 31303b705cfSriastradh 31403b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_WAIT) 31503b705cfSriastradh drm_intel_bo_wait_rendering(intel->batch_bo); 31603b705cfSriastradh 31703b705cfSriastradh intel_next_batch(scrn, intel->current_batch == I915_EXEC_BLT); 31803b705cfSriastradh 31903b705cfSriastradh if (intel->batch_commit_notify) 32003b705cfSriastradh intel->batch_commit_notify(intel); 32103b705cfSriastradh 32203b705cfSriastradh intel->current_batch = 0; 32303b705cfSriastradh} 32403b705cfSriastradh 32513496ba1Ssnjvoid intel_uxa_debug_flush(ScrnInfoPtr scrn) 32603b705cfSriastradh{ 32703b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 32803b705cfSriastradh 32903b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_CACHES) 33003b705cfSriastradh intel_batch_emit_flush(scrn); 33103b705cfSriastradh 33203b705cfSriastradh if (intel->debug_flush & DEBUG_FLUSH_BATCHES) 33303b705cfSriastradh intel_batch_submit(scrn); 33403b705cfSriastradh} 335