i915_dma.c revision 183573
1145132Sanholt/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- 2145132Sanholt */ 3152909Sanholt/*- 4145132Sanholt * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5145132Sanholt * All Rights Reserved. 6182080Srnoland * 7152909Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 8152909Sanholt * copy of this software and associated documentation files (the 9152909Sanholt * "Software"), to deal in the Software without restriction, including 10152909Sanholt * without limitation the rights to use, copy, modify, merge, publish, 11152909Sanholt * distribute, sub license, and/or sell copies of the Software, and to 12152909Sanholt * permit persons to whom the Software is furnished to do so, subject to 13152909Sanholt * the following conditions: 14182080Srnoland * 15152909Sanholt * The above copyright notice and this permission notice (including the 16152909Sanholt * next paragraph) shall be included in all copies or substantial portions 17152909Sanholt * of the Software. 18182080Srnoland * 19152909Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20152909Sanholt * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21152909Sanholt * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22152909Sanholt * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23152909Sanholt * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24152909Sanholt * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25152909Sanholt * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26182080Srnoland * 27152909Sanholt */ 28145132Sanholt 29152909Sanholt#include <sys/cdefs.h> 30152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/i915_dma.c 183573 2008-10-03 16:59:11Z rnoland $"); 31145132Sanholt 32152909Sanholt#include "dev/drm/drmP.h" 33152909Sanholt#include "dev/drm/drm.h" 34152909Sanholt#include "dev/drm/i915_drm.h" 35152909Sanholt#include "dev/drm/i915_drv.h" 36152909Sanholt 37145132Sanholt/* Really want an OS-independent resettable timer. Would like to have 38145132Sanholt * this loop run for (eg) 3 sec, but have the timer reset every time 39145132Sanholt * the head pointer changes, so that EBUSY only happens if the ring 40145132Sanholt * actually stalls for (eg) 3 seconds. 41145132Sanholt */ 42182080Srnolandint i915_wait_ring(struct drm_device * dev, int n, const char *caller) 43145132Sanholt{ 44145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 45145132Sanholt drm_i915_ring_buffer_t *ring = &(dev_priv->ring); 46182080Srnoland u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; 47183573Srnoland u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; 48183573Srnoland u32 last_acthd = I915_READ(acthd_reg); 49183573Srnoland u32 acthd; 50145132Sanholt int i; 51145132Sanholt 52183573Srnoland for (i = 0; i < 100000; i++) { 53182080Srnoland ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; 54183573Srnoland acthd = I915_READ(acthd_reg); 55145132Sanholt ring->space = ring->head - (ring->tail + 8); 56145132Sanholt if (ring->space < 0) 57145132Sanholt ring->space += ring->Size; 58145132Sanholt if (ring->space >= n) 59145132Sanholt return 0; 60145132Sanholt 61145132Sanholt if (ring->head != last_head) 62145132Sanholt i = 0; 63145132Sanholt 64183573Srnoland if (acthd != last_acthd) 65183573Srnoland i = 0; 66183573Srnoland 67145132Sanholt last_head = ring->head; 68183573Srnoland last_acthd = acthd; 69183573Srnoland DRM_UDELAY(10 * 1000); 70145132Sanholt } 71145132Sanholt 72182080Srnoland return -EBUSY; 73145132Sanholt} 74145132Sanholt 75183573Srnolandint i915_init_hardware_status(struct drm_device *dev) 76183573Srnoland{ 77183573Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 78183573Srnoland drm_dma_handle_t *dmah; 79183573Srnoland 80183573Srnoland /* Program Hardware Status Page */ 81183573Srnoland#ifdef __FreeBSD__ 82183573Srnoland DRM_UNLOCK(); 83183573Srnoland#endif 84183573Srnoland dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); 85183573Srnoland#ifdef __FreeBSD__ 86183573Srnoland DRM_LOCK(); 87183573Srnoland#endif 88183573Srnoland if (!dmah) { 89183573Srnoland DRM_ERROR("Can not allocate hardware status page\n"); 90183573Srnoland return -ENOMEM; 91183573Srnoland } 92183573Srnoland 93183573Srnoland dev_priv->status_page_dmah = dmah; 94183573Srnoland dev_priv->hw_status_page = dmah->vaddr; 95183573Srnoland dev_priv->dma_status_page = dmah->busaddr; 96183573Srnoland 97183573Srnoland memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 98183573Srnoland 99183573Srnoland I915_WRITE(0x02080, dev_priv->dma_status_page); 100183573Srnoland DRM_DEBUG("Enabled hardware status page\n"); 101183573Srnoland return 0; 102183573Srnoland} 103183573Srnoland 104183573Srnolandvoid i915_free_hardware_status(struct drm_device *dev) 105183573Srnoland{ 106183573Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 107183573Srnoland if (dev_priv->status_page_dmah) { 108183573Srnoland drm_pci_free(dev, dev_priv->status_page_dmah); 109183573Srnoland dev_priv->status_page_dmah = NULL; 110183573Srnoland /* Need to rewrite hardware status page */ 111183573Srnoland I915_WRITE(0x02080, 0x1ffff000); 112183573Srnoland } 113183573Srnoland 114183573Srnoland if (dev_priv->status_gfx_addr) { 115183573Srnoland dev_priv->status_gfx_addr = 0; 116183573Srnoland drm_core_ioremapfree(&dev_priv->hws_map, dev); 117183573Srnoland I915_WRITE(0x02080, 0x1ffff000); 118183573Srnoland } 119183573Srnoland} 120183573Srnoland 121183573Srnoland#if I915_RING_VALIDATE 122183573Srnoland/** 123183573Srnoland * Validate the cached ring tail value 124183573Srnoland * 125183573Srnoland * If the X server writes to the ring and DRM doesn't 126183573Srnoland * reload the head and tail pointers, it will end up writing 127183573Srnoland * data to the wrong place in the ring, causing havoc. 128183573Srnoland */ 129183573Srnolandvoid i915_ring_validate(struct drm_device *dev, const char *func, int line) 130183573Srnoland{ 131183573Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 132183573Srnoland drm_i915_ring_buffer_t *ring = &(dev_priv->ring); 133183573Srnoland u32 tail = I915_READ(PRB0_TAIL) & HEAD_ADDR; 134183573Srnoland u32 head = I915_READ(PRB0_HEAD) & HEAD_ADDR; 135183573Srnoland 136183573Srnoland if (tail != ring->tail) { 137183573Srnoland DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n", 138183573Srnoland func, line, 139183573Srnoland ring->head, head, ring->tail, tail); 140183573Srnoland#ifdef __linux__ 141183573Srnoland BUG_ON(1); 142183573Srnoland#endif 143183573Srnoland } 144183573Srnoland} 145183573Srnoland#endif 146183573Srnoland 147182080Srnolandvoid i915_kernel_lost_context(struct drm_device * dev) 148145132Sanholt{ 149145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 150145132Sanholt drm_i915_ring_buffer_t *ring = &(dev_priv->ring); 151145132Sanholt 152182080Srnoland ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; 153182080Srnoland ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; 154145132Sanholt ring->space = ring->head - (ring->tail + 8); 155145132Sanholt if (ring->space < 0) 156145132Sanholt ring->space += ring->Size; 157145132Sanholt} 158145132Sanholt 159182080Srnolandstatic int i915_dma_cleanup(struct drm_device * dev) 160145132Sanholt{ 161182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 162145132Sanholt /* Make sure interrupts are disabled here because the uninstall ioctl 163145132Sanholt * may not have been called from userspace and after dev_private 164145132Sanholt * is freed, it's too late. 165145132Sanholt */ 166183573Srnoland if (dev->irq_enabled) 167145132Sanholt drm_irq_uninstall(dev); 168145132Sanholt 169182080Srnoland if (dev_priv->ring.virtual_start) { 170182080Srnoland drm_core_ioremapfree(&dev_priv->ring.map, dev); 171182080Srnoland dev_priv->ring.virtual_start = 0; 172182080Srnoland dev_priv->ring.map.handle = 0; 173182080Srnoland dev_priv->ring.map.size = 0; 174182080Srnoland } 175145132Sanholt 176183573Srnoland if (I915_NEED_GFX_HWS(dev)) 177183573Srnoland i915_free_hardware_status(dev); 178145132Sanholt 179145132Sanholt return 0; 180145132Sanholt} 181145132Sanholt 182182080Srnoland#if defined(I915_HAVE_BUFFER) 183182080Srnoland#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) 184182080Srnoland#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) 185182080Srnoland#define DRI2_SAREA_BLOCK_NEXT(p) \ 186182080Srnoland ((void *) ((unsigned char *) (p) + \ 187182080Srnoland DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p))) 188182080Srnoland 189182080Srnoland#define DRI2_SAREA_BLOCK_END 0x0000 190182080Srnoland#define DRI2_SAREA_BLOCK_LOCK 0x0001 191182080Srnoland#define DRI2_SAREA_BLOCK_EVENT_BUFFER 0x0002 192182080Srnoland 193182080Srnolandstatic int 194182080Srnolandsetup_dri2_sarea(struct drm_device * dev, 195182080Srnoland struct drm_file *file_priv, 196182080Srnoland drm_i915_init_t * init) 197145132Sanholt{ 198182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 199182080Srnoland int ret; 200182080Srnoland unsigned int *p, *end, *next; 201171394Skib 202182080Srnoland mutex_lock(&dev->struct_mutex); 203182080Srnoland dev_priv->sarea_bo = 204182080Srnoland drm_lookup_buffer_object(file_priv, 205182080Srnoland init->sarea_handle, 1); 206182080Srnoland mutex_unlock(&dev->struct_mutex); 207182080Srnoland 208182080Srnoland if (!dev_priv->sarea_bo) { 209182080Srnoland DRM_ERROR("did not find sarea bo\n"); 210182080Srnoland return -EINVAL; 211171394Skib } 212171394Skib 213182080Srnoland ret = drm_bo_kmap(dev_priv->sarea_bo, 0, 214182080Srnoland dev_priv->sarea_bo->num_pages, 215182080Srnoland &dev_priv->sarea_kmap); 216182080Srnoland if (ret) { 217182080Srnoland DRM_ERROR("could not map sarea bo\n"); 218182080Srnoland return ret; 219182080Srnoland } 220145132Sanholt 221182080Srnoland p = dev_priv->sarea_kmap.virtual; 222182080Srnoland end = (void *) p + (dev_priv->sarea_bo->num_pages << PAGE_SHIFT); 223182080Srnoland while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) { 224182080Srnoland switch (DRI2_SAREA_BLOCK_TYPE(*p)) { 225182080Srnoland case DRI2_SAREA_BLOCK_LOCK: 226182080Srnoland dev->lock.hw_lock = (void *) (p + 1); 227182080Srnoland dev->sigdata.lock = dev->lock.hw_lock; 228182080Srnoland break; 229182080Srnoland } 230182080Srnoland next = DRI2_SAREA_BLOCK_NEXT(p); 231182080Srnoland if (next <= p || end < next) { 232182080Srnoland DRM_ERROR("malformed dri2 sarea: next is %p should be within %p-%p\n", 233182080Srnoland next, p, end); 234182080Srnoland return -EINVAL; 235182080Srnoland } 236182080Srnoland p = next; 237182080Srnoland } 238182080Srnoland 239182080Srnoland return 0; 240182080Srnoland} 241182080Srnoland#endif 242182080Srnoland 243182080Srnolandstatic int i915_initialize(struct drm_device * dev, 244182080Srnoland struct drm_file *file_priv, 245182080Srnoland drm_i915_init_t * init) 246182080Srnoland{ 247182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 248182080Srnoland#if defined(I915_HAVE_BUFFER) 249182080Srnoland int ret; 250182080Srnoland#endif 251182080Srnoland dev_priv->sarea = drm_getsarea(dev); 252145132Sanholt if (!dev_priv->sarea) { 253145132Sanholt DRM_ERROR("can not find sarea!\n"); 254145132Sanholt i915_dma_cleanup(dev); 255182080Srnoland return -EINVAL; 256145132Sanholt } 257145132Sanholt 258182080Srnoland#ifdef I915_HAVE_BUFFER 259182080Srnoland dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; 260182080Srnoland#endif 261145132Sanholt 262182080Srnoland if (init->sarea_priv_offset) 263182080Srnoland dev_priv->sarea_priv = (drm_i915_sarea_t *) 264182080Srnoland ((u8 *) dev_priv->sarea->handle + 265182080Srnoland init->sarea_priv_offset); 266182080Srnoland else { 267182080Srnoland /* No sarea_priv for you! */ 268182080Srnoland dev_priv->sarea_priv = NULL; 269182080Srnoland } 270182080Srnoland 271183573Srnoland if (init->ring_size != 0) { 272183573Srnoland dev_priv->ring.Size = init->ring_size; 273183573Srnoland dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; 274145132Sanholt 275183573Srnoland dev_priv->ring.map.offset = init->ring_start; 276183573Srnoland dev_priv->ring.map.size = init->ring_size; 277183573Srnoland dev_priv->ring.map.type = 0; 278183573Srnoland dev_priv->ring.map.flags = 0; 279183573Srnoland dev_priv->ring.map.mtrr = 0; 280145132Sanholt 281183573Srnoland drm_core_ioremap(&dev_priv->ring.map, dev); 282145132Sanholt 283183573Srnoland if (dev_priv->ring.map.handle == NULL) { 284183573Srnoland i915_dma_cleanup(dev); 285183573Srnoland DRM_ERROR("can not ioremap virtual address for" 286183573Srnoland " ring buffer\n"); 287183573Srnoland return -ENOMEM; 288183573Srnoland } 289183573Srnoland 290183573Srnoland dev_priv->ring.virtual_start = dev_priv->ring.map.handle; 291145132Sanholt } 292145132Sanholt 293182080Srnoland dev_priv->cpp = init->cpp; 294145132Sanholt 295182080Srnoland if (dev_priv->sarea_priv) 296182080Srnoland dev_priv->sarea_priv->pf_current_page = 0; 297182080Srnoland 298145132Sanholt /* We are using separate values as placeholders for mechanisms for 299145132Sanholt * private backbuffer/depthbuffer usage. 300145132Sanholt */ 301145132Sanholt 302145132Sanholt /* Allow hardware batchbuffers unless told otherwise. 303145132Sanholt */ 304145132Sanholt dev_priv->allow_batchbuffer = 1; 305145132Sanholt 306182080Srnoland /* Enable vblank on pipe A for older X servers 307182080Srnoland */ 308182080Srnoland dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; 309182080Srnoland 310182080Srnoland#ifdef I915_HAVE_BUFFER 311182080Srnoland mutex_init(&dev_priv->cmdbuf_mutex); 312182080Srnoland#endif 313182080Srnoland#if defined(I915_HAVE_BUFFER) 314182080Srnoland if (init->func == I915_INIT_DMA2) { 315182080Srnoland ret = setup_dri2_sarea(dev, file_priv, init); 316182080Srnoland if (ret) { 317182080Srnoland i915_dma_cleanup(dev); 318182080Srnoland DRM_ERROR("could not set up dri2 sarea\n"); 319182080Srnoland return ret; 320182080Srnoland } 321182080Srnoland } 322182080Srnoland#endif 323145132Sanholt 324145132Sanholt return 0; 325145132Sanholt} 326145132Sanholt 327182080Srnolandstatic int i915_dma_resume(struct drm_device * dev) 328145132Sanholt{ 329145132Sanholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 330145132Sanholt 331182080Srnoland DRM_DEBUG("\n"); 332145132Sanholt 333145132Sanholt if (!dev_priv->sarea) { 334145132Sanholt DRM_ERROR("can not find sarea!\n"); 335182080Srnoland return -EINVAL; 336145132Sanholt } 337145132Sanholt 338145132Sanholt if (dev_priv->ring.map.handle == NULL) { 339145132Sanholt DRM_ERROR("can not ioremap virtual address for" 340145132Sanholt " ring buffer\n"); 341182080Srnoland return -ENOMEM; 342145132Sanholt } 343145132Sanholt 344145132Sanholt /* Program Hardware Status Page */ 345145132Sanholt if (!dev_priv->hw_status_page) { 346145132Sanholt DRM_ERROR("Can not find hardware status page\n"); 347182080Srnoland return -EINVAL; 348145132Sanholt } 349145132Sanholt DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); 350145132Sanholt 351182080Srnoland if (dev_priv->status_gfx_addr != 0) 352182080Srnoland I915_WRITE(0x02080, dev_priv->status_gfx_addr); 353182080Srnoland else 354182080Srnoland I915_WRITE(0x02080, dev_priv->dma_status_page); 355145132Sanholt DRM_DEBUG("Enabled hardware status page\n"); 356145132Sanholt 357145132Sanholt return 0; 358145132Sanholt} 359145132Sanholt 360182080Srnolandstatic int i915_dma_init(struct drm_device *dev, void *data, 361182080Srnoland struct drm_file *file_priv) 362145132Sanholt{ 363182080Srnoland drm_i915_init_t *init = data; 364145132Sanholt int retcode = 0; 365145132Sanholt 366182080Srnoland switch (init->func) { 367145132Sanholt case I915_INIT_DMA: 368182080Srnoland case I915_INIT_DMA2: 369182080Srnoland retcode = i915_initialize(dev, file_priv, init); 370145132Sanholt break; 371145132Sanholt case I915_CLEANUP_DMA: 372145132Sanholt retcode = i915_dma_cleanup(dev); 373145132Sanholt break; 374145132Sanholt case I915_RESUME_DMA: 375145132Sanholt retcode = i915_dma_resume(dev); 376145132Sanholt break; 377145132Sanholt default: 378145132Sanholt retcode = -EINVAL; 379145132Sanholt break; 380145132Sanholt } 381145132Sanholt 382145132Sanholt return retcode; 383145132Sanholt} 384145132Sanholt 385145132Sanholt/* Implement basically the same security restrictions as hardware does 386145132Sanholt * for MI_BATCH_NON_SECURE. These can be made stricter at any time. 387145132Sanholt * 388145132Sanholt * Most of the calculations below involve calculating the size of a 389145132Sanholt * particular instruction. It's important to get the size right as 390145132Sanholt * that tells us where the next instruction to check is. Any illegal 391145132Sanholt * instruction detected will be given a size of zero, which is a 392145132Sanholt * signal to abort the rest of the buffer. 393145132Sanholt */ 394145132Sanholtstatic int do_validate_cmd(int cmd) 395145132Sanholt{ 396145132Sanholt switch (((cmd >> 29) & 0x7)) { 397145132Sanholt case 0x0: 398145132Sanholt switch ((cmd >> 23) & 0x3f) { 399145132Sanholt case 0x0: 400145132Sanholt return 1; /* MI_NOOP */ 401145132Sanholt case 0x4: 402145132Sanholt return 1; /* MI_FLUSH */ 403145132Sanholt default: 404145132Sanholt return 0; /* disallow everything else */ 405145132Sanholt } 406145132Sanholt break; 407145132Sanholt case 0x1: 408145132Sanholt return 0; /* reserved */ 409145132Sanholt case 0x2: 410145132Sanholt return (cmd & 0xff) + 2; /* 2d commands */ 411145132Sanholt case 0x3: 412145132Sanholt if (((cmd >> 24) & 0x1f) <= 0x18) 413145132Sanholt return 1; 414145132Sanholt 415145132Sanholt switch ((cmd >> 24) & 0x1f) { 416145132Sanholt case 0x1c: 417145132Sanholt return 1; 418145132Sanholt case 0x1d: 419145132Sanholt switch ((cmd >> 16) & 0xff) { 420145132Sanholt case 0x3: 421145132Sanholt return (cmd & 0x1f) + 2; 422145132Sanholt case 0x4: 423145132Sanholt return (cmd & 0xf) + 2; 424145132Sanholt default: 425145132Sanholt return (cmd & 0xffff) + 2; 426145132Sanholt } 427145132Sanholt case 0x1e: 428145132Sanholt if (cmd & (1 << 23)) 429145132Sanholt return (cmd & 0xffff) + 1; 430145132Sanholt else 431145132Sanholt return 1; 432145132Sanholt case 0x1f: 433145132Sanholt if ((cmd & (1 << 23)) == 0) /* inline vertices */ 434145132Sanholt return (cmd & 0x1ffff) + 2; 435145132Sanholt else if (cmd & (1 << 17)) /* indirect random */ 436145132Sanholt if ((cmd & 0xffff) == 0) 437145132Sanholt return 0; /* unknown length, too hard */ 438145132Sanholt else 439145132Sanholt return (((cmd & 0xffff) + 1) / 2) + 1; 440145132Sanholt else 441145132Sanholt return 2; /* indirect sequential */ 442145132Sanholt default: 443145132Sanholt return 0; 444145132Sanholt } 445145132Sanholt default: 446145132Sanholt return 0; 447145132Sanholt } 448145132Sanholt 449145132Sanholt return 0; 450145132Sanholt} 451145132Sanholt 452145132Sanholtstatic int validate_cmd(int cmd) 453145132Sanholt{ 454145132Sanholt int ret = do_validate_cmd(cmd); 455145132Sanholt 456182080Srnoland/* printk("validate_cmd( %x ): %d\n", cmd, ret); */ 457145132Sanholt 458145132Sanholt return ret; 459145132Sanholt} 460145132Sanholt 461182080Srnolandstatic int i915_emit_cmds(struct drm_device *dev, int __user *buffer, 462182080Srnoland int dwords) 463145132Sanholt{ 464145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 465145132Sanholt int i; 466145132Sanholt RING_LOCALS; 467145132Sanholt 468157617Sanholt if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) 469182080Srnoland return -EINVAL; 470157617Sanholt 471162132Sanholt BEGIN_LP_RING((dwords+1)&~1); 472157617Sanholt 473145132Sanholt for (i = 0; i < dwords;) { 474145132Sanholt int cmd, sz; 475145132Sanholt 476183573Srnoland if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) 477183573Srnoland return -EINVAL; 478183573Srnoland 479145132Sanholt if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) 480182080Srnoland return -EINVAL; 481145132Sanholt 482145132Sanholt OUT_RING(cmd); 483145132Sanholt 484145132Sanholt while (++i, --sz) { 485183573Srnoland if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], 486183573Srnoland sizeof(cmd))) { 487183573Srnoland return -EINVAL; 488183573Srnoland } 489145132Sanholt OUT_RING(cmd); 490145132Sanholt } 491145132Sanholt } 492182080Srnoland 493157617Sanholt if (dwords & 1) 494157617Sanholt OUT_RING(0); 495145132Sanholt 496157617Sanholt ADVANCE_LP_RING(); 497182080Srnoland 498145132Sanholt return 0; 499145132Sanholt} 500145132Sanholt 501183573Srnolandint i915_emit_box(struct drm_device * dev, 502183573Srnoland struct drm_clip_rect __user * boxes, 503183573Srnoland int i, int DR1, int DR4) 504145132Sanholt{ 505145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 506182080Srnoland struct drm_clip_rect box; 507145132Sanholt RING_LOCALS; 508145132Sanholt 509183573Srnoland if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { 510183573Srnoland return -EFAULT; 511183573Srnoland } 512183573Srnoland 513145132Sanholt if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { 514145132Sanholt DRM_ERROR("Bad box %d,%d..%d,%d\n", 515145132Sanholt box.x1, box.y1, box.x2, box.y2); 516182080Srnoland return -EINVAL; 517145132Sanholt } 518145132Sanholt 519162132Sanholt if (IS_I965G(dev)) { 520162132Sanholt BEGIN_LP_RING(4); 521162132Sanholt OUT_RING(GFX_OP_DRAWRECT_INFO_I965); 522162132Sanholt OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); 523162132Sanholt OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); 524162132Sanholt OUT_RING(DR4); 525162132Sanholt ADVANCE_LP_RING(); 526162132Sanholt } else { 527162132Sanholt BEGIN_LP_RING(6); 528162132Sanholt OUT_RING(GFX_OP_DRAWRECT_INFO); 529162132Sanholt OUT_RING(DR1); 530162132Sanholt OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); 531162132Sanholt OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); 532162132Sanholt OUT_RING(DR4); 533162132Sanholt OUT_RING(0); 534162132Sanholt ADVANCE_LP_RING(); 535162132Sanholt } 536145132Sanholt 537145132Sanholt return 0; 538145132Sanholt} 539145132Sanholt 540162132Sanholt/* XXX: Emitting the counter should really be moved to part of the IRQ 541182080Srnoland * emit. For now, do it in both places: 542162132Sanholt */ 543157617Sanholt 544182080Srnolandvoid i915_emit_breadcrumb(struct drm_device *dev) 545157617Sanholt{ 546157617Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 547157617Sanholt RING_LOCALS; 548157617Sanholt 549182080Srnoland if (++dev_priv->counter > BREADCRUMB_MASK) { 550182080Srnoland dev_priv->counter = 1; 551182080Srnoland DRM_DEBUG("Breadcrumb counter wrapped around\n"); 552182080Srnoland } 553157617Sanholt 554182080Srnoland if (dev_priv->sarea_priv) 555182080Srnoland dev_priv->sarea_priv->last_enqueue = dev_priv->counter; 556162132Sanholt 557157617Sanholt BEGIN_LP_RING(4); 558182080Srnoland OUT_RING(MI_STORE_DWORD_INDEX); 559183573Srnoland OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT); 560157617Sanholt OUT_RING(dev_priv->counter); 561157617Sanholt OUT_RING(0); 562157617Sanholt ADVANCE_LP_RING(); 563157617Sanholt} 564157617Sanholt 565182080Srnoland 566182080Srnolandint i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) 567182080Srnoland{ 568182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 569182080Srnoland uint32_t flush_cmd = MI_FLUSH; 570182080Srnoland RING_LOCALS; 571182080Srnoland 572182080Srnoland flush_cmd |= flush; 573182080Srnoland 574182080Srnoland i915_kernel_lost_context(dev); 575182080Srnoland 576182080Srnoland BEGIN_LP_RING(4); 577182080Srnoland OUT_RING(flush_cmd); 578182080Srnoland OUT_RING(0); 579182080Srnoland OUT_RING(0); 580182080Srnoland OUT_RING(0); 581182080Srnoland ADVANCE_LP_RING(); 582182080Srnoland 583182080Srnoland return 0; 584182080Srnoland} 585182080Srnoland 586182080Srnoland 587182080Srnolandstatic int i915_dispatch_cmdbuffer(struct drm_device * dev, 588145132Sanholt drm_i915_cmdbuffer_t * cmd) 589145132Sanholt{ 590182080Srnoland#ifdef I915_HAVE_FENCE 591182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 592182080Srnoland#endif 593145132Sanholt int nbox = cmd->num_cliprects; 594145132Sanholt int i = 0, count, ret; 595145132Sanholt 596145132Sanholt if (cmd->sz & 0x3) { 597182080Srnoland DRM_ERROR("alignment\n"); 598182080Srnoland return -EINVAL; 599145132Sanholt } 600145132Sanholt 601145132Sanholt i915_kernel_lost_context(dev); 602145132Sanholt 603145132Sanholt count = nbox ? nbox : 1; 604145132Sanholt 605145132Sanholt for (i = 0; i < count; i++) { 606145132Sanholt if (i < nbox) { 607145132Sanholt ret = i915_emit_box(dev, cmd->cliprects, i, 608145132Sanholt cmd->DR1, cmd->DR4); 609145132Sanholt if (ret) 610145132Sanholt return ret; 611145132Sanholt } 612145132Sanholt 613145132Sanholt ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); 614145132Sanholt if (ret) 615145132Sanholt return ret; 616145132Sanholt } 617145132Sanholt 618182080Srnoland i915_emit_breadcrumb(dev); 619182080Srnoland#ifdef I915_HAVE_FENCE 620182080Srnoland if (unlikely((dev_priv->counter & 0xFF) == 0)) 621182080Srnoland drm_fence_flush_old(dev, 0, dev_priv->counter); 622182080Srnoland#endif 623145132Sanholt return 0; 624145132Sanholt} 625145132Sanholt 626182080Srnolandint i915_dispatch_batchbuffer(struct drm_device * dev, 627182080Srnoland drm_i915_batchbuffer_t * batch) 628145132Sanholt{ 629145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 630182080Srnoland struct drm_clip_rect __user *boxes = batch->cliprects; 631145132Sanholt int nbox = batch->num_cliprects; 632145132Sanholt int i = 0, count; 633145132Sanholt RING_LOCALS; 634145132Sanholt 635145132Sanholt if ((batch->start | batch->used) & 0x7) { 636182080Srnoland DRM_ERROR("alignment\n"); 637182080Srnoland return -EINVAL; 638145132Sanholt } 639145132Sanholt 640145132Sanholt i915_kernel_lost_context(dev); 641145132Sanholt 642145132Sanholt count = nbox ? nbox : 1; 643145132Sanholt 644145132Sanholt for (i = 0; i < count; i++) { 645145132Sanholt if (i < nbox) { 646145132Sanholt int ret = i915_emit_box(dev, boxes, i, 647145132Sanholt batch->DR1, batch->DR4); 648145132Sanholt if (ret) 649145132Sanholt return ret; 650145132Sanholt } 651145132Sanholt 652183573Srnoland if (IS_I830(dev) || IS_845G(dev)) { 653183573Srnoland BEGIN_LP_RING(4); 654183573Srnoland OUT_RING(MI_BATCH_BUFFER); 655183573Srnoland OUT_RING(batch->start | MI_BATCH_NON_SECURE); 656183573Srnoland OUT_RING(batch->start + batch->used - 4); 657183573Srnoland OUT_RING(0); 658183573Srnoland ADVANCE_LP_RING(); 659183573Srnoland } else { 660145132Sanholt BEGIN_LP_RING(2); 661182080Srnoland if (IS_I965G(dev)) { 662182080Srnoland OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); 663182080Srnoland OUT_RING(batch->start); 664182080Srnoland } else { 665182080Srnoland OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); 666182080Srnoland OUT_RING(batch->start | MI_BATCH_NON_SECURE); 667182080Srnoland } 668145132Sanholt ADVANCE_LP_RING(); 669145132Sanholt } 670145132Sanholt } 671145132Sanholt 672182080Srnoland i915_emit_breadcrumb(dev); 673182080Srnoland#ifdef I915_HAVE_FENCE 674182080Srnoland if (unlikely((dev_priv->counter & 0xFF) == 0)) 675182080Srnoland drm_fence_flush_old(dev, 0, dev_priv->counter); 676182080Srnoland#endif 677145132Sanholt return 0; 678145132Sanholt} 679145132Sanholt 680182080Srnolandstatic void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) 681145132Sanholt{ 682145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 683182080Srnoland u32 num_pages, current_page, next_page, dspbase; 684182080Srnoland int shift = 2 * plane, x, y; 685145132Sanholt RING_LOCALS; 686145132Sanholt 687182080Srnoland /* Calculate display base offset */ 688182080Srnoland num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; 689182080Srnoland current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; 690182080Srnoland next_page = (current_page + 1) % num_pages; 691145132Sanholt 692182080Srnoland switch (next_page) { 693182080Srnoland default: 694182080Srnoland case 0: 695182080Srnoland dspbase = dev_priv->sarea_priv->front_offset; 696182080Srnoland break; 697182080Srnoland case 1: 698182080Srnoland dspbase = dev_priv->sarea_priv->back_offset; 699182080Srnoland break; 700182080Srnoland case 2: 701182080Srnoland dspbase = dev_priv->sarea_priv->third_offset; 702182080Srnoland break; 703182080Srnoland } 704145132Sanholt 705182080Srnoland if (plane == 0) { 706182080Srnoland x = dev_priv->sarea_priv->planeA_x; 707182080Srnoland y = dev_priv->sarea_priv->planeA_y; 708145132Sanholt } else { 709182080Srnoland x = dev_priv->sarea_priv->planeB_x; 710182080Srnoland y = dev_priv->sarea_priv->planeB_y; 711145132Sanholt } 712145132Sanholt 713182080Srnoland dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; 714145132Sanholt 715182080Srnoland DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, 716182080Srnoland dspbase); 717145132Sanholt 718145132Sanholt BEGIN_LP_RING(4); 719182080Srnoland OUT_RING(sync ? 0 : 720182080Srnoland (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : 721182080Srnoland MI_WAIT_FOR_PLANE_A_FLIP))); 722182080Srnoland OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | 723182080Srnoland (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); 724182080Srnoland OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); 725182080Srnoland OUT_RING(dspbase); 726145132Sanholt ADVANCE_LP_RING(); 727145132Sanholt 728182080Srnoland dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); 729182080Srnoland dev_priv->sarea_priv->pf_current_page |= next_page << shift; 730145132Sanholt} 731145132Sanholt 732182080Srnolandvoid i915_dispatch_flip(struct drm_device * dev, int planes, int sync) 733145132Sanholt{ 734145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 735182080Srnoland int i; 736145132Sanholt 737182080Srnoland DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", 738182080Srnoland planes, dev_priv->sarea_priv->pf_current_page); 739182080Srnoland 740182080Srnoland i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); 741182080Srnoland 742182080Srnoland for (i = 0; i < 2; i++) 743182080Srnoland if (planes & (1 << i)) 744182080Srnoland i915_do_dispatch_flip(dev, i, sync); 745182080Srnoland 746182080Srnoland i915_emit_breadcrumb(dev); 747182080Srnoland#ifdef I915_HAVE_FENCE 748182080Srnoland if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0))) 749182080Srnoland drm_fence_flush_old(dev, 0, dev_priv->counter); 750182080Srnoland#endif 751182080Srnoland} 752182080Srnoland 753182080Srnolandint i915_quiescent(struct drm_device *dev) 754182080Srnoland{ 755182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 756183573Srnoland int ret; 757182080Srnoland 758145132Sanholt i915_kernel_lost_context(dev); 759183573Srnoland ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); 760183573Srnoland if (ret) 761183573Srnoland { 762183573Srnoland i915_kernel_lost_context (dev); 763183573Srnoland DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n", 764183573Srnoland dev_priv->ring.head, 765183573Srnoland dev_priv->ring.tail, 766183573Srnoland dev_priv->ring.space); 767183573Srnoland } 768183573Srnoland return ret; 769145132Sanholt} 770145132Sanholt 771182080Srnolandstatic int i915_flush_ioctl(struct drm_device *dev, void *data, 772182080Srnoland struct drm_file *file_priv) 773145132Sanholt{ 774145132Sanholt 775182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 776145132Sanholt 777145132Sanholt return i915_quiescent(dev); 778145132Sanholt} 779145132Sanholt 780182080Srnolandstatic int i915_batchbuffer(struct drm_device *dev, void *data, 781182080Srnoland struct drm_file *file_priv) 782145132Sanholt{ 783145132Sanholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 784145132Sanholt drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 785145132Sanholt dev_priv->sarea_priv; 786182080Srnoland drm_i915_batchbuffer_t *batch = data; 787145132Sanholt int ret; 788145132Sanholt 789145132Sanholt if (!dev_priv->allow_batchbuffer) { 790145132Sanholt DRM_ERROR("Batchbuffer ioctl disabled\n"); 791182080Srnoland return -EINVAL; 792145132Sanholt } 793145132Sanholt 794145132Sanholt DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", 795182080Srnoland batch->start, batch->used, batch->num_cliprects); 796145132Sanholt 797182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 798145132Sanholt 799182080Srnoland if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, 800183573Srnoland batch->num_cliprects * 801183573Srnoland sizeof(struct drm_clip_rect))) 802182080Srnoland return -EFAULT; 803183573Srnoland 804182080Srnoland ret = i915_dispatch_batchbuffer(dev, batch); 805145132Sanholt 806182080Srnoland sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 807145132Sanholt return ret; 808145132Sanholt} 809145132Sanholt 810182080Srnolandstatic int i915_cmdbuffer(struct drm_device *dev, void *data, 811182080Srnoland struct drm_file *file_priv) 812145132Sanholt{ 813145132Sanholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 814145132Sanholt drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 815145132Sanholt dev_priv->sarea_priv; 816182080Srnoland drm_i915_cmdbuffer_t *cmdbuf = data; 817145132Sanholt int ret; 818145132Sanholt 819145132Sanholt DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", 820182080Srnoland cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); 821145132Sanholt 822182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 823145132Sanholt 824182080Srnoland if (cmdbuf->num_cliprects && 825183573Srnoland DRM_VERIFYAREA_READ(cmdbuf->cliprects, 826183573Srnoland cmdbuf->num_cliprects * 827183573Srnoland sizeof(struct drm_clip_rect))) { 828145132Sanholt DRM_ERROR("Fault accessing cliprects\n"); 829182080Srnoland return -EFAULT; 830145132Sanholt } 831183573Srnoland 832182080Srnoland ret = i915_dispatch_cmdbuffer(dev, cmdbuf); 833183573Srnoland if (ret) { 834145132Sanholt DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); 835183573Srnoland return ret; 836145132Sanholt } 837183573Srnoland 838183573Srnoland sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 839183573Srnoland return 0; 840145132Sanholt} 841145132Sanholt 842182080Srnoland#if defined(DRM_DEBUG_CODE) 843182080Srnoland#define DRM_DEBUG_RELOCATION (drm_debug != 0) 844182080Srnoland#else 845182080Srnoland#define DRM_DEBUG_RELOCATION 0 846182080Srnoland#endif 847182080Srnoland 848182080Srnolandstatic int i915_do_cleanup_pageflip(struct drm_device * dev) 849145132Sanholt{ 850145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 851182080Srnoland int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; 852145132Sanholt 853182080Srnoland DRM_DEBUG("\n"); 854145132Sanholt 855182080Srnoland for (i = 0, planes = 0; i < 2; i++) 856182080Srnoland if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { 857182080Srnoland dev_priv->sarea_priv->pf_current_page = 858182080Srnoland (dev_priv->sarea_priv->pf_current_page & 859182080Srnoland ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); 860182080Srnoland 861182080Srnoland planes |= 1 << i; 862182080Srnoland } 863182080Srnoland 864182080Srnoland if (planes) 865182080Srnoland i915_dispatch_flip(dev, planes, 0); 866182080Srnoland 867145132Sanholt return 0; 868145132Sanholt} 869145132Sanholt 870182080Srnolandstatic int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 871145132Sanholt{ 872182080Srnoland drm_i915_flip_t *param = data; 873145132Sanholt 874182080Srnoland DRM_DEBUG("\n"); 875145132Sanholt 876182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 877145132Sanholt 878182080Srnoland /* This is really planes */ 879182080Srnoland if (param->pipes & ~0x3) { 880182080Srnoland DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n", 881182080Srnoland param->pipes); 882182080Srnoland return -EINVAL; 883182080Srnoland } 884182080Srnoland 885182080Srnoland i915_dispatch_flip(dev, param->pipes, 0); 886182080Srnoland 887182080Srnoland return 0; 888145132Sanholt} 889145132Sanholt 890182080Srnoland 891182080Srnolandstatic int i915_getparam(struct drm_device *dev, void *data, 892182080Srnoland struct drm_file *file_priv) 893145132Sanholt{ 894145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 895182080Srnoland drm_i915_getparam_t *param = data; 896145132Sanholt int value; 897145132Sanholt 898145132Sanholt if (!dev_priv) { 899182080Srnoland DRM_ERROR("called with no initialization\n"); 900182080Srnoland return -EINVAL; 901145132Sanholt } 902145132Sanholt 903182080Srnoland switch (param->param) { 904145132Sanholt case I915_PARAM_IRQ_ACTIVE: 905183573Srnoland value = dev->irq_enabled ? 1 : 0; 906145132Sanholt break; 907145132Sanholt case I915_PARAM_ALLOW_BATCHBUFFER: 908145132Sanholt value = dev_priv->allow_batchbuffer ? 1 : 0; 909145132Sanholt break; 910157617Sanholt case I915_PARAM_LAST_DISPATCH: 911157617Sanholt value = READ_BREADCRUMB(dev_priv); 912157617Sanholt break; 913182080Srnoland case I915_PARAM_CHIPSET_ID: 914182080Srnoland value = dev->pci_device; 915182080Srnoland break; 916183573Srnoland case I915_PARAM_HAS_GEM: 917183573Srnoland value = 1; 918183573Srnoland break; 919145132Sanholt default: 920182080Srnoland DRM_ERROR("Unknown parameter %d\n", param->param); 921182080Srnoland return -EINVAL; 922145132Sanholt } 923145132Sanholt 924182080Srnoland if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 925145132Sanholt DRM_ERROR("DRM_COPY_TO_USER failed\n"); 926182080Srnoland return -EFAULT; 927145132Sanholt } 928145132Sanholt 929145132Sanholt return 0; 930145132Sanholt} 931145132Sanholt 932182080Srnolandstatic int i915_setparam(struct drm_device *dev, void *data, 933182080Srnoland struct drm_file *file_priv) 934145132Sanholt{ 935145132Sanholt drm_i915_private_t *dev_priv = dev->dev_private; 936182080Srnoland drm_i915_setparam_t *param = data; 937145132Sanholt 938145132Sanholt if (!dev_priv) { 939182080Srnoland DRM_ERROR("called with no initialization\n"); 940182080Srnoland return -EINVAL; 941145132Sanholt } 942145132Sanholt 943182080Srnoland switch (param->param) { 944145132Sanholt case I915_SETPARAM_USE_MI_BATCHBUFFER_START: 945145132Sanholt break; 946145132Sanholt case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: 947182080Srnoland dev_priv->tex_lru_log_granularity = param->value; 948145132Sanholt break; 949145132Sanholt case I915_SETPARAM_ALLOW_BATCHBUFFER: 950182080Srnoland dev_priv->allow_batchbuffer = param->value; 951145132Sanholt break; 952145132Sanholt default: 953182080Srnoland DRM_ERROR("unknown parameter %d\n", param->param); 954182080Srnoland return -EINVAL; 955145132Sanholt } 956145132Sanholt 957145132Sanholt return 0; 958145132Sanholt} 959145132Sanholt 960182080Srnolanddrm_i915_mmio_entry_t mmio_table[] = { 961182080Srnoland [MMIO_REGS_PS_DEPTH_COUNT] = { 962182080Srnoland I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, 963182080Srnoland 0x2350, 964182080Srnoland 8 965182080Srnoland } 966182080Srnoland}; 967182080Srnoland 968182080Srnolandstatic int mmio_table_size = sizeof(mmio_table)/sizeof(drm_i915_mmio_entry_t); 969182080Srnoland 970182080Srnolandstatic int i915_mmio(struct drm_device *dev, void *data, 971182080Srnoland struct drm_file *file_priv) 972145132Sanholt{ 973182080Srnoland uint32_t buf[8]; 974182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 975182080Srnoland drm_i915_mmio_entry_t *e; 976182080Srnoland drm_i915_mmio_t *mmio = data; 977182080Srnoland void __iomem *base; 978182080Srnoland int i; 979182080Srnoland 980182080Srnoland if (!dev_priv) { 981182080Srnoland DRM_ERROR("called with no initialization\n"); 982182080Srnoland return -EINVAL; 983182080Srnoland } 984182080Srnoland 985182080Srnoland if (mmio->reg >= mmio_table_size) 986182080Srnoland return -EINVAL; 987182080Srnoland 988182080Srnoland e = &mmio_table[mmio->reg]; 989182080Srnoland base = (u8 *) dev_priv->mmio_map->handle + e->offset; 990182080Srnoland 991182080Srnoland switch (mmio->read_write) { 992182080Srnoland case I915_MMIO_READ: 993182080Srnoland if (!(e->flag & I915_MMIO_MAY_READ)) 994182080Srnoland return -EINVAL; 995182080Srnoland for (i = 0; i < e->size / 4; i++) 996182080Srnoland buf[i] = I915_READ(e->offset + i * 4); 997182080Srnoland if (DRM_COPY_TO_USER(mmio->data, buf, e->size)) { 998182080Srnoland DRM_ERROR("DRM_COPY_TO_USER failed\n"); 999182080Srnoland return -EFAULT; 1000182080Srnoland } 1001182080Srnoland break; 1002182080Srnoland 1003182080Srnoland case I915_MMIO_WRITE: 1004182080Srnoland if (!(e->flag & I915_MMIO_MAY_WRITE)) 1005182080Srnoland return -EINVAL; 1006182080Srnoland if (DRM_COPY_FROM_USER(buf, mmio->data, e->size)) { 1007182080Srnoland DRM_ERROR("DRM_COPY_TO_USER failed\n"); 1008182080Srnoland return -EFAULT; 1009182080Srnoland } 1010182080Srnoland for (i = 0; i < e->size / 4; i++) 1011182080Srnoland I915_WRITE(e->offset + i * 4, buf[i]); 1012182080Srnoland break; 1013182080Srnoland } 1014182080Srnoland return 0; 1015182080Srnoland} 1016182080Srnoland 1017182080Srnolandstatic int i915_set_status_page(struct drm_device *dev, void *data, 1018182080Srnoland struct drm_file *file_priv) 1019182080Srnoland{ 1020182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 1021182080Srnoland drm_i915_hws_addr_t *hws = data; 1022182080Srnoland 1023182080Srnoland if (!I915_NEED_GFX_HWS(dev)) 1024182080Srnoland return -EINVAL; 1025182080Srnoland 1026182080Srnoland if (!dev_priv) { 1027182080Srnoland DRM_ERROR("called with no initialization\n"); 1028182080Srnoland return -EINVAL; 1029182080Srnoland } 1030182080Srnoland DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr); 1031182080Srnoland 1032182080Srnoland dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); 1033182080Srnoland 1034182080Srnoland dev_priv->hws_map.offset = dev->agp->base + hws->addr; 1035182080Srnoland dev_priv->hws_map.size = 4*1024; 1036182080Srnoland dev_priv->hws_map.type = 0; 1037182080Srnoland dev_priv->hws_map.flags = 0; 1038182080Srnoland dev_priv->hws_map.mtrr = 0; 1039182080Srnoland 1040182080Srnoland drm_core_ioremap(&dev_priv->hws_map, dev); 1041182080Srnoland if (dev_priv->hws_map.handle == NULL) { 1042182080Srnoland i915_dma_cleanup(dev); 1043182080Srnoland dev_priv->status_gfx_addr = 0; 1044182080Srnoland DRM_ERROR("can not ioremap virtual address for" 1045182080Srnoland " G33 hw status page\n"); 1046182080Srnoland return -ENOMEM; 1047182080Srnoland } 1048182080Srnoland dev_priv->hw_status_page = dev_priv->hws_map.handle; 1049182080Srnoland 1050182080Srnoland memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 1051182080Srnoland I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); 1052182080Srnoland DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", 1053182080Srnoland dev_priv->status_gfx_addr); 1054182080Srnoland DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); 1055182080Srnoland return 0; 1056182080Srnoland} 1057182080Srnoland 1058182080Srnolandint i915_driver_load(struct drm_device *dev, unsigned long flags) 1059182080Srnoland{ 1060182080Srnoland struct drm_i915_private *dev_priv; 1061182080Srnoland unsigned long base, size; 1062182080Srnoland int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; 1063182080Srnoland 1064152909Sanholt /* i915 has 4 more counters */ 1065152909Sanholt dev->counters += 4; 1066152909Sanholt dev->types[6] = _DRM_STAT_IRQ; 1067152909Sanholt dev->types[7] = _DRM_STAT_PRIMARY; 1068152909Sanholt dev->types[8] = _DRM_STAT_SECONDARY; 1069152909Sanholt dev->types[9] = _DRM_STAT_DMA; 1070152909Sanholt 1071182080Srnoland dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); 1072182080Srnoland if (dev_priv == NULL) 1073182080Srnoland return -ENOMEM; 1074182080Srnoland 1075182080Srnoland memset(dev_priv, 0, sizeof(drm_i915_private_t)); 1076182080Srnoland 1077182080Srnoland dev->dev_private = (void *)dev_priv; 1078183573Srnoland dev_priv->dev = dev; 1079182080Srnoland 1080182080Srnoland /* Add register map (needed for suspend/resume) */ 1081182080Srnoland base = drm_get_resource_start(dev, mmio_bar); 1082182080Srnoland size = drm_get_resource_len(dev, mmio_bar); 1083182080Srnoland 1084182080Srnoland ret = drm_addmap(dev, base, size, _DRM_REGISTERS, 1085182080Srnoland _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map); 1086183573Srnoland#ifdef I915_HAVE_GEM 1087183573Srnoland i915_gem_load(dev); 1088183573Srnoland#endif 1089182080Srnoland DRM_SPININIT(&dev_priv->swaps_lock, "swap"); 1090182080Srnoland DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); 1091182080Srnoland 1092182080Srnoland#ifdef __linux__ 1093182080Srnoland#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) 1094182080Srnoland intel_init_chipset_flush_compat(dev); 1095182080Srnoland#endif 1096182080Srnoland#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) 1097182080Srnoland intel_opregion_init(dev); 1098182080Srnoland#endif 1099182080Srnoland#endif 1100182080Srnoland 1101183573Srnoland /* Init HWS */ 1102183573Srnoland if (!I915_NEED_GFX_HWS(dev)) { 1103183573Srnoland ret = i915_init_hardware_status(dev); 1104183573Srnoland if(ret) 1105183573Srnoland return ret; 1106183573Srnoland } 1107183573Srnoland 1108182080Srnoland return ret; 1109182080Srnoland} 1110182080Srnoland 1111182080Srnolandint i915_driver_unload(struct drm_device *dev) 1112182080Srnoland{ 1113182080Srnoland struct drm_i915_private *dev_priv = dev->dev_private; 1114182080Srnoland 1115183573Srnoland i915_free_hardware_status(dev); 1116182080Srnoland 1117183573Srnoland drm_rmmap(dev, dev_priv->mmio_map); 1118183573Srnoland 1119182080Srnoland DRM_SPINUNINIT(&dev_priv->swaps_lock); 1120182080Srnoland DRM_SPINUNINIT(&dev_priv->user_irq_lock); 1121182080Srnoland 1122182080Srnoland#ifdef __linux__ 1123182080Srnoland#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) 1124182080Srnoland intel_opregion_free(dev); 1125182080Srnoland#endif 1126182080Srnoland#endif 1127182080Srnoland 1128182080Srnoland drm_free(dev->dev_private, sizeof(drm_i915_private_t), 1129182080Srnoland DRM_MEM_DRIVER); 1130182080Srnoland dev->dev_private = NULL; 1131182080Srnoland 1132182080Srnoland#ifdef __linux__ 1133182080Srnoland#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) 1134182080Srnoland intel_fini_chipset_flush_compat(dev); 1135182080Srnoland#endif 1136182080Srnoland#endif 1137152909Sanholt return 0; 1138152909Sanholt} 1139152909Sanholt 1140182080Srnolandvoid i915_driver_lastclose(struct drm_device * dev) 1141152909Sanholt{ 1142182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 1143182080Srnoland 1144182080Srnoland /* agp off can use this to get called before dev_priv */ 1145182080Srnoland if (!dev_priv) 1146182080Srnoland return; 1147182080Srnoland 1148182080Srnoland#ifdef I915_HAVE_BUFFER 1149182080Srnoland if (dev_priv->val_bufs) { 1150182080Srnoland vfree(dev_priv->val_bufs); 1151182080Srnoland dev_priv->val_bufs = NULL; 1152182080Srnoland } 1153182080Srnoland#endif 1154183573Srnoland#ifdef I915_HAVE_GEM 1155183573Srnoland i915_gem_lastclose(dev); 1156183573Srnoland#endif 1157183573Srnoland if (drm_getsarea(dev) && dev_priv->sarea_priv) 1158182080Srnoland i915_do_cleanup_pageflip(dev); 1159183573Srnoland if (dev_priv->sarea_priv) 1160182080Srnoland dev_priv->sarea_priv = NULL; 1161182080Srnoland if (dev_priv->agp_heap) 1162145132Sanholt i915_mem_takedown(&(dev_priv->agp_heap)); 1163182080Srnoland#if defined(I915_HAVE_BUFFER) 1164182080Srnoland if (dev_priv->sarea_kmap.virtual) { 1165182080Srnoland drm_bo_kunmap(&dev_priv->sarea_kmap); 1166182080Srnoland dev_priv->sarea_kmap.virtual = NULL; 1167182080Srnoland dev->lock.hw_lock = NULL; 1168182080Srnoland dev->sigdata.lock = NULL; 1169145132Sanholt } 1170182080Srnoland 1171182080Srnoland if (dev_priv->sarea_bo) { 1172182080Srnoland mutex_lock(&dev->struct_mutex); 1173182080Srnoland drm_bo_usage_deref_locked(&dev_priv->sarea_bo); 1174182080Srnoland mutex_unlock(&dev->struct_mutex); 1175182080Srnoland dev_priv->sarea_bo = NULL; 1176182080Srnoland } 1177182080Srnoland#endif 1178145132Sanholt i915_dma_cleanup(dev); 1179145132Sanholt} 1180145132Sanholt 1181183573Srnolandint i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) 1182183573Srnoland{ 1183183573Srnoland struct drm_i915_file_private *i915_file_priv; 1184183573Srnoland 1185183573Srnoland DRM_DEBUG("\n"); 1186183573Srnoland i915_file_priv = (struct drm_i915_file_private *) 1187183573Srnoland drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); 1188183573Srnoland 1189183573Srnoland if (!i915_file_priv) 1190183573Srnoland return -ENOMEM; 1191183573Srnoland 1192183573Srnoland file_priv->driver_priv = i915_file_priv; 1193183573Srnoland 1194183573Srnoland i915_file_priv->mm.last_gem_seqno = 0; 1195183573Srnoland i915_file_priv->mm.last_gem_throttle_seqno = 0; 1196183573Srnoland 1197183573Srnoland return 0; 1198183573Srnoland} 1199183573Srnoland 1200182080Srnolandvoid i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) 1201145132Sanholt{ 1202182080Srnoland drm_i915_private_t *dev_priv = dev->dev_private; 1203182080Srnoland i915_mem_release(dev, file_priv, dev_priv->agp_heap); 1204145132Sanholt} 1205145132Sanholt 1206183573Srnolandvoid i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) 1207183573Srnoland{ 1208183573Srnoland struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; 1209183573Srnoland 1210183573Srnoland drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); 1211183573Srnoland} 1212183573Srnoland 1213182080Srnolandstruct drm_ioctl_desc i915_ioctls[] = { 1214182080Srnoland DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1215182080Srnoland DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), 1216182080Srnoland DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), 1217182080Srnoland DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), 1218182080Srnoland DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), 1219182080Srnoland DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), 1220182080Srnoland DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), 1221182080Srnoland DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1222182080Srnoland DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), 1223182080Srnoland DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), 1224182080Srnoland DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1225182080Srnoland DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), 1226182080Srnoland DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), 1227182080Srnoland DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), 1228182080Srnoland DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), 1229182080Srnoland DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), 1230182080Srnoland DRM_IOCTL_DEF(DRM_I915_MMIO, i915_mmio, DRM_AUTH), 1231182080Srnoland DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), 1232182080Srnoland#ifdef I915_HAVE_BUFFER 1233182080Srnoland DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH), 1234182080Srnoland#endif 1235183573Srnoland#ifdef I915_HAVE_GEM 1236183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH), 1237183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), 1238183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 1239183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), 1240183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), 1241183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), 1242183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH), 1243183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH), 1244183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), 1245183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), 1246183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), 1247183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), 1248183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), 1249183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), 1250183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), 1251183573Srnoland DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0), 1252183573Srnoland#endif 1253145132Sanholt}; 1254145132Sanholt 1255145132Sanholtint i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); 1256152909Sanholt 1257152909Sanholt/** 1258152909Sanholt * Determine if the device really is AGP or not. 1259152909Sanholt * 1260152909Sanholt * All Intel graphics chipsets are treated as AGP, even if they are really 1261152909Sanholt * PCI-e. 1262152909Sanholt * 1263152909Sanholt * \param dev The device to be tested. 1264152909Sanholt * 1265152909Sanholt * \returns 1266152909Sanholt * A value of 1 is always retured to indictate every i9x5 is AGP. 1267152909Sanholt */ 1268182080Srnolandint i915_driver_device_is_agp(struct drm_device * dev) 1269152909Sanholt{ 1270152909Sanholt return 1; 1271152909Sanholt} 1272182080Srnoland 1273182080Srnolandint i915_driver_firstopen(struct drm_device *dev) 1274182080Srnoland{ 1275182080Srnoland#ifdef I915_HAVE_BUFFER 1276182080Srnoland drm_bo_driver_init(dev); 1277182080Srnoland#endif 1278182080Srnoland return 0; 1279182080Srnoland} 1280