···9696 chipset. If M is selected the module will be called sis. AGP9797 support is required for this driver to work.98989999+config DRM_VIA100100+ tristate "Via unichrome video cards"101101+ depends on DRM102102+ help103103+ Choose this option if you have a Via unichrome or compatible video104104+ chipset. If M is selected the module will be called via.105105+
···11+/* via_dma.c -- DMA support for the VIA Unichrome/Pro22+ * 33+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.44+ * All Rights Reserved.55+ *66+ * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.77+ * All Rights Reserved.88+ * 99+ * Copyright 2004 The Unichrome project.1010+ * All Rights Reserved.1111+ *1212+ * Permission is hereby granted, free of charge, to any person obtaining a1313+ * copy of this software and associated documentation files (the "Software"),1414+ * to deal in the Software without restriction, including without limitation1515+ * the rights to use, copy, modify, merge, publish, distribute, sub license,1616+ * and/or sell copies of the Software, and to permit persons to whom the1717+ * Software is furnished to do so, subject to the following conditions:1818+ *1919+ * The above copyright notice and this permission notice (including the2020+ * next paragraph) shall be included in all copies or substantial portions2121+ * of the Software.2222+ *2323+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR2424+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,2525+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL2626+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2727+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2828+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2929+ * USE OR OTHER DEALINGS IN THE SOFTWARE.3030+ *3131+ * Authors: 3232+ * Tungsten Graphics, 3333+ * Erdi Chen, 3434+ * Thomas Hellstrom.3535+ */3636+3737+#include "drmP.h"3838+#include "drm.h"3939+#include "via_drm.h"4040+#include "via_drv.h"4141+#include "via_3d_reg.h"4242+4343+#define CMDBUF_ALIGNMENT_SIZE (0x100)4444+#define CMDBUF_ALIGNMENT_MASK (0x0ff)4545+4646+/* defines for VIA 3D registers */4747+#define VIA_REG_STATUS 0x4004848+#define VIA_REG_TRANSET 0x43C4949+#define VIA_REG_TRANSPACE 0x4405050+5151+/* VIA_REG_STATUS(0x400): Engine Status */5252+#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */5353+#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */5454+#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */5555+#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */5656+5757+#define SetReg2DAGP(nReg, nData) { \5858+ *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \5959+ *((uint32_t *)(vb) + 1) = (nData); \6060+ vb = ((uint32_t *)vb) + 2; \6161+ dev_priv->dma_low +=8; \6262+}6363+6464+#define via_flush_write_combine() DRM_MEMORYBARRIER() 6565+6666+#define VIA_OUT_RING_QW(w1,w2) \6767+ *vb++ = (w1); \6868+ *vb++ = (w2); \6969+ dev_priv->dma_low += 8; 7070+7171+static void via_cmdbuf_start(drm_via_private_t * dev_priv);7272+static void via_cmdbuf_pause(drm_via_private_t * dev_priv);7373+static void via_cmdbuf_reset(drm_via_private_t * dev_priv);7474+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);7575+static int via_wait_idle(drm_via_private_t * dev_priv);7676+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);7777+7878+7979+/*8080+ * Free space in command buffer.8181+ */8282+8383+static uint32_t8484+via_cmdbuf_space(drm_via_private_t *dev_priv)8585+{8686+ uint32_t agp_base = dev_priv->dma_offset + 8787+ (uint32_t) dev_priv->agpAddr;8888+ uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;8989+9090+ return ((hw_addr <= dev_priv->dma_low) ? 9191+ (dev_priv->dma_high + hw_addr - dev_priv->dma_low) : 9292+ (hw_addr - dev_priv->dma_low));9393+}9494+9595+/*9696+ * How much does the command regulator lag behind?9797+ */9898+9999+static uint32_t100100+via_cmdbuf_lag(drm_via_private_t *dev_priv)101101+{102102+ uint32_t agp_base = dev_priv->dma_offset + 103103+ (uint32_t) dev_priv->agpAddr;104104+ uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;105105+106106+ return ((hw_addr <= dev_priv->dma_low) ? 107107+ (dev_priv->dma_low - hw_addr) : 108108+ (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));109109+}110110+111111+/*112112+ * Check that the given size fits in the buffer, otherwise wait.113113+ */114114+115115+static inline int116116+via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)117117+{118118+ uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;119119+ uint32_t cur_addr, hw_addr, next_addr;120120+ volatile uint32_t *hw_addr_ptr;121121+ uint32_t count;122122+ hw_addr_ptr = dev_priv->hw_addr_ptr;123123+ cur_addr = dev_priv->dma_low;124124+ next_addr = cur_addr + size + 512*1024;125125+ count = 1000000;126126+ do {127127+ hw_addr = *hw_addr_ptr - agp_base;128128+ if (count-- == 0) {129129+ DRM_ERROR("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",130130+ hw_addr, cur_addr, next_addr);131131+ return -1;132132+ }133133+ } while ((cur_addr < hw_addr) && (next_addr >= hw_addr));134134+ return 0;135135+}136136+137137+138138+/*139139+ * Checks whether buffer head has reach the end. Rewind the ring buffer140140+ * when necessary.141141+ *142142+ * Returns virtual pointer to ring buffer.143143+ */144144+145145+static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,146146+ unsigned int size)147147+{148148+ if ((dev_priv->dma_low + size + 4*CMDBUF_ALIGNMENT_SIZE) > dev_priv->dma_high) {149149+ via_cmdbuf_rewind(dev_priv);150150+ }151151+ if (via_cmdbuf_wait(dev_priv, size) != 0) {152152+ return NULL;153153+ }154154+155155+ return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);156156+}157157+158158+int via_dma_cleanup(drm_device_t * dev)159159+{160160+ if (dev->dev_private) {161161+ drm_via_private_t *dev_priv =162162+ (drm_via_private_t *) dev->dev_private;163163+164164+ if (dev_priv->ring.virtual_start) {165165+ via_cmdbuf_reset(dev_priv);166166+167167+ drm_core_ioremapfree(&dev_priv->ring.map, dev);168168+ dev_priv->ring.virtual_start = NULL;169169+ }170170+171171+ }172172+173173+ return 0;174174+}175175+176176+static int via_initialize(drm_device_t * dev,177177+ drm_via_private_t * dev_priv,178178+ drm_via_dma_init_t * init)179179+{180180+ if (!dev_priv || !dev_priv->mmio) {181181+ DRM_ERROR("via_dma_init called before via_map_init\n");182182+ return DRM_ERR(EFAULT);183183+ }184184+185185+ if (dev_priv->ring.virtual_start != NULL) {186186+ DRM_ERROR("%s called again without calling cleanup\n",187187+ __FUNCTION__);188188+ return DRM_ERR(EFAULT);189189+ }190190+191191+ if (!dev->agp || !dev->agp->base) {192192+ DRM_ERROR("%s called with no agp memory available\n", 193193+ __FUNCTION__);194194+ return DRM_ERR(EFAULT);195195+ }196196+197197+ dev_priv->ring.map.offset = dev->agp->base + init->offset;198198+ dev_priv->ring.map.size = init->size;199199+ dev_priv->ring.map.type = 0;200200+ dev_priv->ring.map.flags = 0;201201+ dev_priv->ring.map.mtrr = 0;202202+203203+ drm_core_ioremap(&dev_priv->ring.map, dev);204204+205205+ if (dev_priv->ring.map.handle == NULL) {206206+ via_dma_cleanup(dev);207207+ DRM_ERROR("can not ioremap virtual address for"208208+ " ring buffer\n");209209+ return DRM_ERR(ENOMEM);210210+ }211211+212212+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;213213+214214+ dev_priv->dma_ptr = dev_priv->ring.virtual_start;215215+ dev_priv->dma_low = 0;216216+ dev_priv->dma_high = init->size;217217+ dev_priv->dma_wrap = init->size;218218+ dev_priv->dma_offset = init->offset;219219+ dev_priv->last_pause_ptr = NULL;220220+ dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr;221221+222222+ via_cmdbuf_start(dev_priv);223223+224224+ return 0;225225+}226226+227227+int via_dma_init(DRM_IOCTL_ARGS)228228+{229229+ DRM_DEVICE;230230+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;231231+ drm_via_dma_init_t init;232232+ int retcode = 0;233233+234234+ DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *) data,235235+ sizeof(init));236236+237237+ switch (init.func) {238238+ case VIA_INIT_DMA:239239+ if (!capable(CAP_SYS_ADMIN))240240+ retcode = DRM_ERR(EPERM);241241+ else242242+ retcode = via_initialize(dev, dev_priv, &init);243243+ break;244244+ case VIA_CLEANUP_DMA:245245+ if (!capable(CAP_SYS_ADMIN))246246+ retcode = DRM_ERR(EPERM);247247+ else248248+ retcode = via_dma_cleanup(dev);249249+ break;250250+ case VIA_DMA_INITIALIZED:251251+ retcode = (dev_priv->ring.virtual_start != NULL) ? 252252+ 0: DRM_ERR( EFAULT );253253+ break;254254+ default:255255+ retcode = DRM_ERR(EINVAL);256256+ break;257257+ }258258+259259+ return retcode;260260+}261261+262262+263263+264264+static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)265265+{266266+ drm_via_private_t *dev_priv;267267+ uint32_t *vb;268268+ int ret;269269+270270+ dev_priv = (drm_via_private_t *) dev->dev_private;271271+272272+ if (dev_priv->ring.virtual_start == NULL) {273273+ DRM_ERROR("%s called without initializing AGP ring buffer.\n",274274+ __FUNCTION__);275275+ return DRM_ERR(EFAULT);276276+ }277277+278278+ if (cmd->size > VIA_PCI_BUF_SIZE) {279279+ return DRM_ERR(ENOMEM);280280+ } 281281+282282+283283+ if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))284284+ return DRM_ERR(EFAULT);285285+286286+ /*287287+ * Running this function on AGP memory is dead slow. Therefore288288+ * we run it on a temporary cacheable system memory buffer and289289+ * copy it to AGP memory when ready.290290+ */291291+292292+293293+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) {294294+ return ret;295295+ }296296+297297+298298+ vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);299299+ if (vb == NULL) {300300+ return DRM_ERR(EAGAIN);301301+ }302302+303303+ memcpy(vb, dev_priv->pci_buf, cmd->size);304304+305305+ dev_priv->dma_low += cmd->size;306306+307307+ /*308308+ * Small submissions somehow stalls the CPU. (AGP cache effects?)309309+ * pad to greater size.310310+ */311311+312312+ if (cmd->size < 0x100)313313+ via_pad_cache(dev_priv,(0x100 - cmd->size) >> 3);314314+ via_cmdbuf_pause(dev_priv);315315+316316+ return 0;317317+}318318+319319+int via_driver_dma_quiescent(drm_device_t * dev)320320+{321321+ drm_via_private_t *dev_priv = dev->dev_private;322322+323323+ if (!via_wait_idle(dev_priv)) {324324+ return DRM_ERR(EBUSY);325325+ }326326+ return 0;327327+}328328+329329+int via_flush_ioctl(DRM_IOCTL_ARGS)330330+{331331+ DRM_DEVICE;332332+333333+ LOCK_TEST_WITH_RETURN( dev, filp );334334+335335+ return via_driver_dma_quiescent(dev);336336+}337337+338338+int via_cmdbuffer(DRM_IOCTL_ARGS)339339+{340340+ DRM_DEVICE;341341+ drm_via_cmdbuffer_t cmdbuf;342342+ int ret;343343+344344+ LOCK_TEST_WITH_RETURN( dev, filp );345345+346346+ DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,347347+ sizeof(cmdbuf));348348+349349+ DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);350350+351351+ ret = via_dispatch_cmdbuffer(dev, &cmdbuf);352352+ if (ret) {353353+ return ret;354354+ }355355+356356+ return 0;357357+}358358+359359+extern int 360360+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size);361361+static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,362362+ drm_via_cmdbuffer_t * cmd)363363+{364364+ drm_via_private_t *dev_priv = dev->dev_private;365365+ int ret;366366+367367+ if (cmd->size > VIA_PCI_BUF_SIZE) {368368+ return DRM_ERR(ENOMEM);369369+ } 370370+ if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))371371+ return DRM_ERR(EFAULT);372372+373373+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) {374374+ return ret;375375+ }376376+377377+ ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size);378378+ return ret;379379+}380380+381381+int via_pci_cmdbuffer(DRM_IOCTL_ARGS)382382+{383383+ DRM_DEVICE;384384+ drm_via_cmdbuffer_t cmdbuf;385385+ int ret;386386+387387+ LOCK_TEST_WITH_RETURN( dev, filp );388388+389389+ DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,390390+ sizeof(cmdbuf));391391+392392+ DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,393393+ cmdbuf.size);394394+395395+ ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);396396+ if (ret) {397397+ return ret;398398+ }399399+400400+ return 0;401401+}402402+403403+404404+static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,405405+ uint32_t * vb, int qw_count)406406+{407407+ for (; qw_count > 0; --qw_count) {408408+ VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);409409+ }410410+ return vb;411411+}412412+413413+414414+/*415415+ * This function is used internally by ring buffer mangement code.416416+ *417417+ * Returns virtual pointer to ring buffer.418418+ */419419+static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)420420+{421421+ return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);422422+}423423+424424+/*425425+ * Hooks a segment of data into the tail of the ring-buffer by426426+ * modifying the pause address stored in the buffer itself. If427427+ * the regulator has already paused, restart it.428428+ */429429+static int via_hook_segment(drm_via_private_t *dev_priv,430430+ uint32_t pause_addr_hi, uint32_t pause_addr_lo,431431+ int no_pci_fire)432432+{433433+ int paused, count;434434+ volatile uint32_t *paused_at = dev_priv->last_pause_ptr;435435+436436+ via_flush_write_combine();437437+ while(! *(via_get_dma(dev_priv)-1));438438+ *dev_priv->last_pause_ptr = pause_addr_lo;439439+ via_flush_write_combine();440440+441441+ /*442442+ * The below statement is inserted to really force the flush.443443+ * Not sure it is needed.444444+ */445445+446446+ while(! *dev_priv->last_pause_ptr);447447+ dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;448448+ while(! *dev_priv->last_pause_ptr);449449+450450+451451+ paused = 0;452452+ count = 20; 453453+454454+ while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);455455+ if ((count <= 8) && (count >= 0)) {456456+ uint32_t rgtr, ptr;457457+ rgtr = *(dev_priv->hw_addr_ptr);458458+ ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + 459459+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - 460460+ CMDBUF_ALIGNMENT_SIZE;461461+ if (rgtr <= ptr) {462462+ DRM_ERROR("Command regulator\npaused at count %d, address %x, "463463+ "while current pause address is %x.\n"464464+ "Please mail this message to "465465+ "<unichrome-devel@lists.sourceforge.net>\n",466466+ count, rgtr, ptr);467467+ }468468+ }469469+470470+ if (paused && !no_pci_fire) {471471+ uint32_t rgtr,ptr;472472+ uint32_t ptr_low;473473+474474+ count = 1000000;475475+ while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) && count--);476476+477477+ rgtr = *(dev_priv->hw_addr_ptr);478478+ ptr = ((char *)paused_at - dev_priv->dma_ptr) + 479479+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;480480+481481+482482+ ptr_low = (ptr > 3*CMDBUF_ALIGNMENT_SIZE) ? 483483+ ptr - 3*CMDBUF_ALIGNMENT_SIZE : 0;484484+ if (rgtr <= ptr && rgtr >= ptr_low) {485485+ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));486486+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);487487+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);488488+ } 489489+ }490490+ return paused;491491+}492492+493493+494494+495495+static int via_wait_idle(drm_via_private_t * dev_priv)496496+{497497+ int count = 10000000;498498+ while (count-- && (VIA_READ(VIA_REG_STATUS) &499499+ (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |500500+ VIA_3D_ENG_BUSY))) ;501501+ return count;502502+}503503+504504+static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,505505+ uint32_t addr, uint32_t *cmd_addr_hi, 506506+ uint32_t *cmd_addr_lo,507507+ int skip_wait)508508+{509509+ uint32_t agp_base;510510+ uint32_t cmd_addr, addr_lo, addr_hi;511511+ uint32_t *vb;512512+ uint32_t qw_pad_count;513513+514514+ if (!skip_wait)515515+ via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);516516+517517+ vb = via_get_dma(dev_priv);518518+ VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |519519+ (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); 520520+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;521521+ qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -522522+ ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);523523+524524+525525+ cmd_addr = (addr) ? addr : 526526+ agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);527527+ addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |528528+ (cmd_addr & HC_HAGPBpL_MASK));529529+ addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));530530+531531+ vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);532532+ VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, 533533+ *cmd_addr_lo = addr_lo);534534+ return vb;535535+}536536+537537+538538+539539+540540+static void via_cmdbuf_start(drm_via_private_t * dev_priv)541541+{542542+ uint32_t pause_addr_lo, pause_addr_hi;543543+ uint32_t start_addr, start_addr_lo;544544+ uint32_t end_addr, end_addr_lo;545545+ uint32_t command;546546+ uint32_t agp_base;547547+548548+549549+ dev_priv->dma_low = 0;550550+551551+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;552552+ start_addr = agp_base;553553+ end_addr = agp_base + dev_priv->dma_high;554554+555555+ start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));556556+ end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));557557+ command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |558558+ ((end_addr & 0xff000000) >> 16));559559+560560+ dev_priv->last_pause_ptr = 561561+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, 562562+ &pause_addr_hi, & pause_addr_lo, 1) - 1;563563+564564+ via_flush_write_combine();565565+ while(! *dev_priv->last_pause_ptr);566566+567567+ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));568568+ VIA_WRITE(VIA_REG_TRANSPACE, command);569569+ VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);570570+ VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);571571+572572+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);573573+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);574574+575575+ VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);576576+}577577+578578+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)579579+{580580+ uint32_t *vb;581581+582582+ via_cmdbuf_wait(dev_priv, qwords + 2);583583+ vb = via_get_dma(dev_priv);584584+ VIA_OUT_RING_QW( HC_HEADER2, HC_ParaType_NotTex << 16);585585+ via_align_buffer(dev_priv,vb,qwords);586586+}587587+588588+static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)589589+{590590+ uint32_t *vb = via_get_dma(dev_priv);591591+ SetReg2DAGP(0x0C, (0 | (0 << 16)));592592+ SetReg2DAGP(0x10, 0 | (0 << 16));593593+ SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); 594594+}595595+596596+597597+static void via_cmdbuf_jump(drm_via_private_t * dev_priv)598598+{599599+ uint32_t agp_base;600600+ uint32_t pause_addr_lo, pause_addr_hi;601601+ uint32_t jump_addr_lo, jump_addr_hi;602602+ volatile uint32_t *last_pause_ptr;603603+ uint32_t dma_low_save1, dma_low_save2;604604+605605+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;606606+ via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, 607607+ &jump_addr_lo, 0);608608+609609+ dev_priv->dma_wrap = dev_priv->dma_low;610610+611611+612612+ /*613613+ * Wrap command buffer to the beginning.614614+ */615615+616616+ dev_priv->dma_low = 0;617617+ if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {618618+ DRM_ERROR("via_cmdbuf_jump failed\n");619619+ }620620+621621+ via_dummy_bitblt(dev_priv);622622+ via_dummy_bitblt(dev_priv); 623623+624624+ last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 625625+ &pause_addr_lo, 0) -1;626626+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 627627+ &pause_addr_lo, 0);628628+629629+ *last_pause_ptr = pause_addr_lo;630630+ dma_low_save1 = dev_priv->dma_low;631631+632632+ /*633633+ * Now, set a trap that will pause the regulator if it tries to rerun the old634634+ * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause635635+ * and reissues the jump command over PCI, while the regulator has already taken the jump636636+ * and actually paused at the current buffer end).637637+ * There appears to be no other way to detect this condition, since the hw_addr_pointer638638+ * does not seem to get updated immediately when a jump occurs.639639+ */640640+641641+ last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 642642+ &pause_addr_lo, 0) -1;643643+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 644644+ &pause_addr_lo, 0);645645+ *last_pause_ptr = pause_addr_lo;646646+647647+ dma_low_save2 = dev_priv->dma_low;648648+ dev_priv->dma_low = dma_low_save1; 649649+ via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);650650+ dev_priv->dma_low = dma_low_save2;651651+ via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);652652+}653653+654654+655655+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)656656+{657657+ via_cmdbuf_jump(dev_priv); 658658+}659659+660660+static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)661661+{662662+ uint32_t pause_addr_lo, pause_addr_hi;663663+664664+ via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);665665+ via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);666666+}667667+668668+669669+static void via_cmdbuf_pause(drm_via_private_t * dev_priv)670670+{671671+ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);672672+}673673+674674+static void via_cmdbuf_reset(drm_via_private_t * dev_priv)675675+{676676+ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);677677+ via_wait_idle(dev_priv);678678+}679679+680680+/*681681+ * User interface to the space and lag functions.682682+ */683683+684684+int 685685+via_cmdbuf_size(DRM_IOCTL_ARGS)686686+{687687+ DRM_DEVICE;688688+ drm_via_cmdbuf_size_t d_siz;689689+ int ret = 0;690690+ uint32_t tmp_size, count;691691+ drm_via_private_t *dev_priv;692692+693693+ DRM_DEBUG("via cmdbuf_size\n");694694+ LOCK_TEST_WITH_RETURN( dev, filp );695695+696696+ dev_priv = (drm_via_private_t *) dev->dev_private;697697+698698+ if (dev_priv->ring.virtual_start == NULL) {699699+ DRM_ERROR("%s called without initializing AGP ring buffer.\n",700700+ __FUNCTION__);701701+ return DRM_ERR(EFAULT);702702+ }703703+704704+ DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t *) data,705705+ sizeof(d_siz));706706+707707+708708+ count = 1000000;709709+ tmp_size = d_siz.size;710710+ switch(d_siz.func) {711711+ case VIA_CMDBUF_SPACE:712712+ while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size) && count--) {713713+ if (!d_siz.wait) {714714+ break;715715+ }716716+ }717717+ if (!count) {718718+ DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");719719+ ret = DRM_ERR(EAGAIN);720720+ }721721+ break;722722+ case VIA_CMDBUF_LAG:723723+ while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size) && count--) {724724+ if (!d_siz.wait) {725725+ break;726726+ }727727+ }728728+ if (!count) {729729+ DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");730730+ ret = DRM_ERR(EAGAIN);731731+ }732732+ break;733733+ default:734734+ ret = DRM_ERR(EFAULT);735735+ }736736+ d_siz.size = tmp_size;737737+738738+ DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t *) data, d_siz,739739+ sizeof(d_siz));740740+ return ret;741741+}
+243
drivers/char/drm/via_drm.h
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+#ifndef _VIA_DRM_H_2525+#define _VIA_DRM_H_2626+2727+/* WARNING: These defines must be the same as what the Xserver uses.2828+ * if you change them, you must change the defines in the Xserver.2929+ */3030+3131+#ifndef _VIA_DEFINES_3232+#define _VIA_DEFINES_3333+3434+#ifndef __KERNEL__3535+#include "via_drmclient.h"3636+#endif3737+3838+#define VIA_NR_SAREA_CLIPRECTS 83939+#define VIA_NR_XVMC_PORTS 104040+#define VIA_NR_XVMC_LOCKS 54141+#define VIA_MAX_CACHELINE_SIZE 644242+#define XVMCLOCKPTR(saPriv,lockNo) \4343+ ((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \4444+ (VIA_MAX_CACHELINE_SIZE - 1)) & \4545+ ~(VIA_MAX_CACHELINE_SIZE - 1)) + \4646+ VIA_MAX_CACHELINE_SIZE*(lockNo)))4747+4848+/* Each region is a minimum of 64k, and there are at most 64 of them.4949+ */5050+#define VIA_NR_TEX_REGIONS 645151+#define VIA_LOG_MIN_TEX_REGION_SIZE 165252+#endif5353+5454+#define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */5555+#define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */5656+#define VIA_UPLOAD_CTX 0x45757+#define VIA_UPLOAD_BUFFERS 0x85858+#define VIA_UPLOAD_TEX0 0x105959+#define VIA_UPLOAD_TEX1 0x206060+#define VIA_UPLOAD_CLIPRECTS 0x406161+#define VIA_UPLOAD_ALL 0xff6262+6363+/* VIA specific ioctls */6464+#define DRM_VIA_ALLOCMEM 0x006565+#define DRM_VIA_FREEMEM 0x016666+#define DRM_VIA_AGP_INIT 0x026767+#define DRM_VIA_FB_INIT 0x036868+#define DRM_VIA_MAP_INIT 0x046969+#define DRM_VIA_DEC_FUTEX 0x057070+#define NOT_USED7171+#define DRM_VIA_DMA_INIT 0x077272+#define DRM_VIA_CMDBUFFER 0x087373+#define DRM_VIA_FLUSH 0x097474+#define DRM_VIA_PCICMD 0x0a7575+#define DRM_VIA_CMDBUF_SIZE 0x0b7676+#define NOT_USED7777+#define DRM_VIA_WAIT_IRQ 0x0d7878+7979+#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)8080+#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)8181+#define DRM_IOCTL_VIA_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t)8282+#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t)8383+#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t)8484+#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t)8585+#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t)8686+#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t)8787+#define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH)8888+#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)8989+#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \9090+ drm_via_cmdbuf_size_t)9191+#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)9292+9393+/* Indices into buf.Setup where various bits of state are mirrored per9494+ * context and per buffer. These can be fired at the card as a unit,9595+ * or in a piecewise fashion as required.9696+ */9797+9898+#define VIA_TEX_SETUP_SIZE 89999+100100+/* Flags for clear ioctl101101+ */102102+#define VIA_FRONT 0x1103103+#define VIA_BACK 0x2104104+#define VIA_DEPTH 0x4105105+#define VIA_STENCIL 0x8106106+#define VIDEO 0107107+#define AGP 1108108+typedef struct {109109+ uint32_t offset;110110+ uint32_t size;111111+} drm_via_agp_t;112112+113113+typedef struct {114114+ uint32_t offset;115115+ uint32_t size;116116+} drm_via_fb_t;117117+118118+typedef struct {119119+ uint32_t context;120120+ uint32_t type;121121+ uint32_t size;122122+ unsigned long index;123123+ unsigned long offset;124124+} drm_via_mem_t;125125+126126+typedef struct _drm_via_init {127127+ enum {128128+ VIA_INIT_MAP = 0x01,129129+ VIA_CLEANUP_MAP = 0x02130130+ } func;131131+132132+ unsigned long sarea_priv_offset;133133+ unsigned long fb_offset;134134+ unsigned long mmio_offset;135135+ unsigned long agpAddr;136136+} drm_via_init_t;137137+138138+typedef struct _drm_via_futex {139139+ enum {140140+ VIA_FUTEX_WAIT = 0x00,141141+ VIA_FUTEX_WAKE = 0X01142142+ } func;143143+ uint32_t ms;144144+ uint32_t lock;145145+ uint32_t val;146146+} drm_via_futex_t;147147+148148+typedef struct _drm_via_dma_init {149149+ enum {150150+ VIA_INIT_DMA = 0x01,151151+ VIA_CLEANUP_DMA = 0x02,152152+ VIA_DMA_INITIALIZED = 0x03153153+ } func;154154+155155+ unsigned long offset;156156+ unsigned long size;157157+ unsigned long reg_pause_addr;158158+} drm_via_dma_init_t;159159+160160+typedef struct _drm_via_cmdbuffer {161161+ char *buf;162162+ unsigned long size;163163+} drm_via_cmdbuffer_t;164164+165165+/* Warning: If you change the SAREA structure you must change the Xserver166166+ * structure as well */167167+168168+typedef struct _drm_via_tex_region {169169+ unsigned char next, prev; /* indices to form a circular LRU */170170+ unsigned char inUse; /* owned by a client, or free? */171171+ int age; /* tracked by clients to update local LRU's */172172+} drm_via_tex_region_t;173173+174174+typedef struct _drm_via_sarea {175175+ unsigned int dirty;176176+ unsigned int nbox;177177+ drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS];178178+ drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1];179179+ int texAge; /* last time texture was uploaded */180180+ int ctxOwner; /* last context to upload state */181181+ int vertexPrim;182182+183183+ /*184184+ * Below is for XvMC.185185+ * We want the lock integers alone on, and aligned to, a cache line.186186+ * Therefore this somewhat strange construct.187187+ */188188+189189+ char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)];190190+191191+ unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS];192192+ unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS];193193+ unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */194194+195195+} drm_via_sarea_t;196196+197197+typedef struct _drm_via_cmdbuf_size {198198+ enum {199199+ VIA_CMDBUF_SPACE = 0x01,200200+ VIA_CMDBUF_LAG = 0x02201201+ } func;202202+ int wait;203203+ uint32_t size;204204+} drm_via_cmdbuf_size_t;205205+206206+typedef enum {207207+ VIA_IRQ_ABSOLUTE = 0x0,208208+ VIA_IRQ_RELATIVE = 0x1,209209+ VIA_IRQ_SIGNAL = 0x10000000,210210+ VIA_IRQ_FORCE_SEQUENCE = 0x20000000211211+} via_irq_seq_type_t;212212+213213+#define VIA_IRQ_FLAGS_MASK 0xF0000000214214+215215+struct drm_via_wait_irq_request{216216+ unsigned irq;217217+ via_irq_seq_type_t type;218218+ uint32_t sequence;219219+ uint32_t signal;220220+};221221+222222+typedef union drm_via_irqwait {223223+ struct drm_via_wait_irq_request request;224224+ struct drm_wait_vblank_reply reply;225225+} drm_via_irqwait_t;226226+227227+#ifdef __KERNEL__228228+229229+int via_fb_init(DRM_IOCTL_ARGS);230230+int via_mem_alloc(DRM_IOCTL_ARGS);231231+int via_mem_free(DRM_IOCTL_ARGS);232232+int via_agp_init(DRM_IOCTL_ARGS);233233+int via_map_init(DRM_IOCTL_ARGS);234234+int via_decoder_futex(DRM_IOCTL_ARGS);235235+int via_dma_init(DRM_IOCTL_ARGS);236236+int via_cmdbuffer(DRM_IOCTL_ARGS);237237+int via_flush_ioctl(DRM_IOCTL_ARGS);238238+int via_pci_cmdbuffer(DRM_IOCTL_ARGS);239239+int via_cmdbuf_size(DRM_IOCTL_ARGS);240240+int via_wait_irq(DRM_IOCTL_ARGS);241241+242242+#endif243243+#endif /* _VIA_DRM_H_ */
+126
drivers/char/drm/via_drv.c
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+2525+#include <linux/config.h>2626+#include "drmP.h"2727+#include "via_drm.h"2828+#include "via_drv.h"2929+3030+#include "drm_pciids.h"3131+3232+static int postinit(struct drm_device *dev, unsigned long flags)3333+{3434+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n",3535+ DRIVER_NAME,3636+ DRIVER_MAJOR,3737+ DRIVER_MINOR,3838+ DRIVER_PATCHLEVEL,3939+ DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev)4040+ );4141+ return 0;4242+}4343+4444+static int version(drm_version_t * version)4545+{4646+ int len;4747+4848+ version->version_major = DRIVER_MAJOR;4949+ version->version_minor = DRIVER_MINOR;5050+ version->version_patchlevel = DRIVER_PATCHLEVEL;5151+ DRM_COPY(version->name, DRIVER_NAME);5252+ DRM_COPY(version->date, DRIVER_DATE);5353+ DRM_COPY(version->desc, DRIVER_DESC);5454+ return 0;5555+}5656+5757+static struct pci_device_id pciidlist[] = {5858+ viadrv_PCI_IDS5959+};6060+6161+static drm_ioctl_desc_t ioctls[] = {6262+ [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0},6363+ [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0},6464+ [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0},6565+ [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0},6666+ [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0},6767+ [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0},6868+ [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0},6969+ [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0},7070+ [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0},7171+ [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0},7272+ [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0},7373+ [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0}7474+};7575+7676+static struct drm_driver driver = {7777+ .driver_features =7878+ DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |7979+ DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,8080+ .context_ctor = via_init_context,8181+ .context_dtor = via_final_context,8282+ .vblank_wait = via_driver_vblank_wait,8383+ .irq_preinstall = via_driver_irq_preinstall,8484+ .irq_postinstall = via_driver_irq_postinstall,8585+ .irq_uninstall = via_driver_irq_uninstall,8686+ .irq_handler = via_driver_irq_handler,8787+ .dma_quiescent = via_driver_dma_quiescent,8888+ .reclaim_buffers = drm_core_reclaim_buffers,8989+ .get_map_ofs = drm_core_get_map_ofs,9090+ .get_reg_ofs = drm_core_get_reg_ofs,9191+ .postinit = postinit,9292+ .version = version,9393+ .ioctls = ioctls,9494+ .num_ioctls = DRM_ARRAY_SIZE(ioctls),9595+ .fops = {9696+ .owner = THIS_MODULE,9797+ .open = drm_open,9898+ .release = drm_release,9999+ .ioctl = drm_ioctl,100100+ .mmap = drm_mmap,101101+ .poll = drm_poll,102102+ .fasync = drm_fasync,103103+ },104104+ .pci_driver = {105105+ .name = DRIVER_NAME,106106+ .id_table = pciidlist,107107+ }108108+};109109+110110+static int __init via_init(void)111111+{112112+ via_init_command_verifier();113113+ return drm_init(&driver);114114+}115115+116116+static void __exit via_exit(void)117117+{118118+ drm_exit(&driver);119119+}120120+121121+module_init(via_init);122122+module_exit(via_exit);123123+124124+MODULE_AUTHOR(DRIVER_AUTHOR);125125+MODULE_DESCRIPTION(DRIVER_DESC);126126+MODULE_LICENSE("GPL and additional rights");
+118
drivers/char/drm/via_drv.h
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+#ifndef _VIA_DRV_H_2525+#define _VIA_DRV_H_2626+2727+#define DRIVER_AUTHOR "VIA"2828+2929+#define DRIVER_NAME "via"3030+#define DRIVER_DESC "VIA Unichrome / Pro"3131+#define DRIVER_DATE "20050523"3232+3333+#define DRIVER_MAJOR 23434+#define DRIVER_MINOR 63535+#define DRIVER_PATCHLEVEL 33636+3737+#include "via_verifier.h"3838+3939+#define VIA_PCI_BUF_SIZE 600004040+#define VIA_FIRE_BUF_SIZE 10244141+#define VIA_NUM_IRQS 24242+4343+4444+4545+typedef struct drm_via_ring_buffer {4646+ drm_map_t map;4747+ char *virtual_start;4848+} drm_via_ring_buffer_t;4949+5050+typedef uint32_t maskarray_t[5];5151+5252+typedef struct drm_via_irq {5353+ atomic_t irq_received;5454+ uint32_t pending_mask;5555+ uint32_t enable_mask;5656+ wait_queue_head_t irq_queue;5757+} drm_via_irq_t;5858+5959+typedef struct drm_via_private {6060+ drm_via_sarea_t *sarea_priv;6161+ drm_map_t *sarea;6262+ drm_map_t *fb;6363+ drm_map_t *mmio;6464+ unsigned long agpAddr;6565+ wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];6666+ char *dma_ptr;6767+ unsigned int dma_low;6868+ unsigned int dma_high;6969+ unsigned int dma_offset;7070+ uint32_t dma_wrap;7171+ volatile uint32_t *last_pause_ptr;7272+ volatile uint32_t *hw_addr_ptr;7373+ drm_via_ring_buffer_t ring;7474+ struct timeval last_vblank;7575+ int last_vblank_valid;7676+ unsigned usec_per_vblank;7777+ drm_via_state_t hc_state;7878+ char pci_buf[VIA_PCI_BUF_SIZE];7979+ const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];8080+ uint32_t num_fire_offsets;8181+ int pro_group_a;8282+ drm_via_irq_t via_irqs[VIA_NUM_IRQS];8383+ unsigned num_irqs;8484+ maskarray_t *irq_masks;8585+ uint32_t irq_enable_mask; 8686+ uint32_t irq_pending_mask; 8787+} drm_via_private_t;8888+8989+/* VIA MMIO register access */9090+#define VIA_BASE ((dev_priv->mmio))9191+9292+#define VIA_READ(reg) DRM_READ32(VIA_BASE, reg)9393+#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val)9494+#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)9595+#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)9696+9797+extern int via_init_context(drm_device_t * dev, int context);9898+extern int via_final_context(drm_device_t * dev, int context);9999+100100+extern int via_do_cleanup_map(drm_device_t * dev);101101+extern int via_map_init(struct inode *inode, struct file *filp,102102+ unsigned int cmd, unsigned long arg);103103+extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);104104+105105+extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);106106+extern void via_driver_irq_preinstall(drm_device_t * dev);107107+extern void via_driver_irq_postinstall(drm_device_t * dev);108108+extern void via_driver_irq_uninstall(drm_device_t * dev);109109+110110+extern int via_dma_cleanup(drm_device_t * dev);111111+extern void via_init_command_verifier(void);112112+extern int via_driver_dma_quiescent(drm_device_t * dev);113113+extern void via_init_futex(drm_via_private_t *dev_priv);114114+extern void via_cleanup_futex(drm_via_private_t *dev_priv);115115+extern void via_release_futex(drm_via_private_t *dev_priv, int context);116116+117117+118118+#endif
+280
drivers/char/drm/via_ds.c
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.55+ *66+ * Permission is hereby granted, free of charge, to any person obtaining a77+ * copy of this software and associated documentation files (the "Software"),88+ * to deal in the Software without restriction, including without limitation99+ * the rights to use, copy, modify, merge, publish, distribute, sub license,1010+ * and/or sell copies of the Software, and to permit persons to whom the1111+ * Software is furnished to do so, subject to the following conditions:1212+ *1313+ * The above copyright notice and this permission notice (including the1414+ * next paragraph) shall be included in all copies or substantial portions1515+ * of the Software.1616+ *1717+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1818+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1919+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL2020+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2121+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2222+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2323+ * DEALINGS IN THE SOFTWARE.2424+ */2525+#include <linux/module.h>2626+#include <linux/delay.h>2727+#include <linux/errno.h>2828+#include <linux/kernel.h>2929+#include <linux/slab.h>3030+#include <linux/poll.h>3131+#include <linux/pci.h>3232+#include <asm/io.h>3333+3434+#include "via_ds.h"3535+extern unsigned int VIA_DEBUG;3636+3737+set_t *via_setInit(void)3838+{3939+ int i;4040+ set_t *set;4141+ set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);4242+ for (i = 0; i < SET_SIZE; i++) {4343+ set->list[i].free_next = i + 1;4444+ set->list[i].alloc_next = -1;4545+ }4646+ set->list[SET_SIZE - 1].free_next = -1;4747+ set->free = 0;4848+ set->alloc = -1;4949+ set->trace = -1;5050+ return set;5151+}5252+5353+int via_setAdd(set_t * set, ITEM_TYPE item)5454+{5555+ int free = set->free;5656+ if (free != -1) {5757+ set->list[free].val = item;5858+ set->free = set->list[free].free_next;5959+ } else {6060+ return 0;6161+ }6262+ set->list[free].alloc_next = set->alloc;6363+ set->alloc = free;6464+ set->list[free].free_next = -1;6565+ return 1;6666+}6767+6868+int via_setDel(set_t * set, ITEM_TYPE item)6969+{7070+ int alloc = set->alloc;7171+ int prev = -1;7272+7373+ while (alloc != -1) {7474+ if (set->list[alloc].val == item) {7575+ if (prev != -1)7676+ set->list[prev].alloc_next =7777+ set->list[alloc].alloc_next;7878+ else7979+ set->alloc = set->list[alloc].alloc_next;8080+ break;8181+ }8282+ prev = alloc;8383+ alloc = set->list[alloc].alloc_next;8484+ }8585+8686+ if (alloc == -1)8787+ return 0;8888+8989+ set->list[alloc].free_next = set->free;9090+ set->free = alloc;9191+ set->list[alloc].alloc_next = -1;9292+9393+ return 1;9494+}9595+9696+/* setFirst -> setAdd -> setNext is wrong */9797+9898+int via_setFirst(set_t * set, ITEM_TYPE * item)9999+{100100+ if (set->alloc == -1)101101+ return 0;102102+103103+ *item = set->list[set->alloc].val;104104+ set->trace = set->list[set->alloc].alloc_next;105105+106106+ return 1;107107+}108108+109109+int via_setNext(set_t * set, ITEM_TYPE * item)110110+{111111+ if (set->trace == -1)112112+ return 0;113113+114114+ *item = set->list[set->trace].val;115115+ set->trace = set->list[set->trace].alloc_next;116116+117117+ return 1;118118+}119119+120120+int via_setDestroy(set_t * set)121121+{122122+ drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);123123+124124+ return 1;125125+}126126+127127+#define ISFREE(bptr) ((bptr)->free)128128+129129+#define fprintf(fmt, arg...) do{}while(0)130130+131131+memHeap_t *via_mmInit(int ofs, int size)132132+{133133+ PMemBlock blocks;134134+135135+ if (size <= 0)136136+ return 0;137137+138138+ blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);139139+140140+ if (blocks) {141141+ blocks->ofs = ofs;142142+ blocks->size = size;143143+ blocks->free = 1;144144+ return (memHeap_t *) blocks;145145+ } else146146+ return 0;147147+}148148+149149+static TMemBlock *SliceBlock(TMemBlock * p,150150+ int startofs, int size,151151+ int reserved, int alignment)152152+{153153+ TMemBlock *newblock;154154+155155+ /* break left */156156+ if (startofs > p->ofs) {157157+ newblock =158158+ (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),159159+ DRM_MEM_DRIVER);160160+ newblock->ofs = startofs;161161+ newblock->size = p->size - (startofs - p->ofs);162162+ newblock->free = 1;163163+ newblock->next = p->next;164164+ p->size -= newblock->size;165165+ p->next = newblock;166166+ p = newblock;167167+ }168168+169169+ /* break right */170170+ if (size < p->size) {171171+ newblock =172172+ (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),173173+ DRM_MEM_DRIVER);174174+ newblock->ofs = startofs + size;175175+ newblock->size = p->size - size;176176+ newblock->free = 1;177177+ newblock->next = p->next;178178+ p->size = size;179179+ p->next = newblock;180180+ }181181+182182+ /* p = middle block */183183+ p->align = alignment;184184+ p->free = 0;185185+ p->reserved = reserved;186186+ return p;187187+}188188+189189+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,190190+ int startSearch)191191+{192192+ int mask, startofs, endofs;193193+ TMemBlock *p;194194+195195+ if (!heap || align2 < 0 || size <= 0)196196+ return NULL;197197+198198+ mask = (1 << align2) - 1;199199+ startofs = 0;200200+ p = (TMemBlock *) heap;201201+202202+ while (p) {203203+ if (ISFREE(p)) {204204+ startofs = (p->ofs + mask) & ~mask;205205+206206+ if (startofs < startSearch)207207+ startofs = startSearch;208208+209209+ endofs = startofs + size;210210+211211+ if (endofs <= (p->ofs + p->size))212212+ break;213213+ }214214+215215+ p = p->next;216216+ }217217+218218+ if (!p)219219+ return NULL;220220+221221+ p = SliceBlock(p, startofs, size, 0, mask + 1);222222+ p->heap = heap;223223+224224+ return p;225225+}226226+227227+static __inline__ int Join2Blocks(TMemBlock * p)228228+{229229+ if (p->free && p->next && p->next->free) {230230+ TMemBlock *q = p->next;231231+ p->size += q->size;232232+ p->next = q->next;233233+ drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);234234+235235+ return 1;236236+ }237237+238238+ return 0;239239+}240240+241241+int via_mmFreeMem(PMemBlock b)242242+{243243+ TMemBlock *p, *prev;244244+245245+ if (!b)246246+ return 0;247247+248248+ if (!b->heap) {249249+ fprintf(stderr, "no heap\n");250250+251251+ return -1;252252+ }253253+254254+ p = b->heap;255255+ prev = NULL;256256+257257+ while (p && p != b) {258258+ prev = p;259259+ p = p->next;260260+ }261261+262262+ if (!p || p->free || p->reserved) {263263+ if (!p)264264+ fprintf(stderr, "block not found in heap\n");265265+ else if (p->free)266266+ fprintf(stderr, "block already free\n");267267+ else268268+ fprintf(stderr, "block is reserved\n");269269+270270+ return -1;271271+ }272272+273273+ p->free = 1;274274+ Join2Blocks(p);275275+276276+ if (prev)277277+ Join2Blocks(prev);278278+279279+ return 0;280280+}
+104
drivers/char/drm/via_ds.h
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.55+ * All rights reserved.66+ *77+ * Permission is hereby granted, free of charge, to any person obtaining a88+ * copy of this software and associated documentation files (the "Software"),99+ * to deal in the Software without restriction, including without limitation1010+ * the rights to use, copy, modify, merge, publish, distribute, sub license,1111+ * and/or sell copies of the Software, and to permit persons to whom the1212+ * Software is furnished to do so, subject to the following conditions:1313+ *1414+ * The above copyright notice and this permission notice (including the1515+ * next paragraph) shall be included in all copies or substantial portions1616+ * of the Software.1717+ *1818+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1919+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,2020+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL2121+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2222+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2323+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2424+ * DEALINGS IN THE SOFTWARE.2525+ */2626+#ifndef _via_ds_h_2727+#define _via_ds_h_2828+2929+#include "drmP.h"3030+3131+/* Set Data Structure */3232+#define SET_SIZE 50003333+typedef unsigned long ITEM_TYPE;3434+3535+typedef struct {3636+ ITEM_TYPE val;3737+ int alloc_next, free_next;3838+} list_item_t;3939+4040+typedef struct {4141+ int alloc;4242+ int free;4343+ int trace;4444+ list_item_t list[SET_SIZE];4545+} set_t;4646+4747+set_t *via_setInit(void);4848+int via_setAdd(set_t * set, ITEM_TYPE item);4949+int via_setDel(set_t * set, ITEM_TYPE item);5050+int via_setFirst(set_t * set, ITEM_TYPE * item);5151+int via_setNext(set_t * set, ITEM_TYPE * item);5252+int via_setDestroy(set_t * set);5353+5454+#endif5555+5656+#ifndef MM_INC5757+#define MM_INC5858+5959+struct mem_block_t {6060+ struct mem_block_t *next;6161+ struct mem_block_t *heap;6262+ int ofs, size;6363+ int align;6464+ int free:1;6565+ int reserved:1;6666+};6767+typedef struct mem_block_t TMemBlock;6868+typedef struct mem_block_t *PMemBlock;6969+7070+/* a heap is just the first block in a chain */7171+typedef struct mem_block_t memHeap_t;7272+7373+static __inline__ int mmBlockSize(PMemBlock b)7474+{7575+ return b->size;7676+}7777+7878+static __inline__ int mmOffset(PMemBlock b)7979+{8080+ return b->ofs;8181+}8282+8383+static __inline__ void mmMarkReserved(PMemBlock b)8484+{8585+ b->reserved = 1;8686+}8787+8888+/*8989+ * input: total size in bytes9090+ * return: a heap pointer if OK, NULL if error9191+ */9292+memHeap_t *via_mmInit(int ofs, int size);9393+9494+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,9595+ int startSearch);9696+9797+/*9898+ * Free block starts at offset9999+ * input: pointer to a block100100+ * return: 0 if OK, -1 if error101101+ */102102+int via_mmFreeMem(PMemBlock b);103103+104104+#endif
+339
drivers/char/drm/via_irq.c
···11+/* via_irq.c22+ *33+ * Copyright 2004 BEAM Ltd.44+ * Copyright 2002 Tungsten Graphics, Inc.55+ * Copyright 2005 Thomas Hellstrom.66+ * All Rights Reserved.77+ *88+ * Permission is hereby granted, free of charge, to any person obtaining a99+ * copy of this software and associated documentation files (the "Software"),1010+ * to deal in the Software without restriction, including without limitation1111+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,1212+ * and/or sell copies of the Software, and to permit persons to whom the1313+ * Software is furnished to do so, subject to the following conditions:1414+ *1515+ * The above copyright notice and this permission notice (including the next1616+ * paragraph) shall be included in all copies or substantial portions of the1717+ * Software.1818+ *1919+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR2020+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,2121+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL2222+ * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,2323+ * DAMAGES OR2424+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2525+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2626+ * DEALINGS IN THE SOFTWARE.2727+ *2828+ * Authors:2929+ * Terry Barnaby <terry1@beam.ltd.uk>3030+ * Keith Whitwell <keith@tungstengraphics.com>3131+ * Thomas Hellstrom <unichrome@shipmail.org>3232+ *3333+ * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank3434+ * interrupt, as well as an infrastructure to handle other interrupts of the chip.3535+ * The refresh rate is also calculated for video playback sync purposes.3636+ */3737+3838+#include "drmP.h"3939+#include "drm.h"4040+#include "via_drm.h"4141+#include "via_drv.h"4242+4343+#define VIA_REG_INTERRUPT 0x2004444+4545+/* VIA_REG_INTERRUPT */4646+#define VIA_IRQ_GLOBAL (1 << 31)4747+#define VIA_IRQ_VBLANK_ENABLE (1 << 19)4848+#define VIA_IRQ_VBLANK_PENDING (1 << 3)4949+#define VIA_IRQ_HQV0_ENABLE (1 << 11)5050+#define VIA_IRQ_HQV1_ENABLE (1 << 25)5151+#define VIA_IRQ_HQV0_PENDING (1 << 9)5252+#define VIA_IRQ_HQV1_PENDING (1 << 10)5353+5454+/*5555+ * Device-specific IRQs go here. This type might need to be extended with5656+ * the register if there are multiple IRQ control registers.5757+ * Currently we activate the HQV interrupts of Unichrome Pro group A. 5858+ */5959+6060+static maskarray_t via_pro_group_a_irqs[] = {6161+ {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },6262+ {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};6363+static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);6464+6565+static maskarray_t via_unichrome_irqs[] = {};6666+static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);6767+6868+6969+static unsigned time_diff(struct timeval *now,struct timeval *then) 7070+{7171+ return (now->tv_usec >= then->tv_usec) ?7272+ now->tv_usec - then->tv_usec :7373+ 1000000 - (then->tv_usec - now->tv_usec);7474+}7575+7676+irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)7777+{7878+ drm_device_t *dev = (drm_device_t *) arg;7979+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;8080+ u32 status;8181+ int handled = 0;8282+ struct timeval cur_vblank;8383+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;8484+ int i;8585+8686+ status = VIA_READ(VIA_REG_INTERRUPT);8787+ if (status & VIA_IRQ_VBLANK_PENDING) {8888+ atomic_inc(&dev->vbl_received);8989+ if (!(atomic_read(&dev->vbl_received) & 0x0F)) {9090+ do_gettimeofday(&cur_vblank);9191+ if (dev_priv->last_vblank_valid) {9292+ dev_priv->usec_per_vblank = 9393+ time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;9494+ }9595+ dev_priv->last_vblank = cur_vblank;9696+ dev_priv->last_vblank_valid = 1;9797+ }9898+ if (!(atomic_read(&dev->vbl_received) & 0xFF)) {9999+ DRM_DEBUG("US per vblank is: %u\n",100100+ dev_priv->usec_per_vblank);101101+ }102102+ DRM_WAKEUP(&dev->vbl_queue);103103+ drm_vbl_send_signals(dev);104104+ handled = 1;105105+ }106106+107107+108108+ for (i=0; i<dev_priv->num_irqs; ++i) {109109+ if (status & cur_irq->pending_mask) {110110+ atomic_inc( &cur_irq->irq_received );111111+ DRM_WAKEUP( &cur_irq->irq_queue );112112+ handled = 1;113113+ }114114+ cur_irq++;115115+ }116116+117117+ /* Acknowlege interrupts */118118+ VIA_WRITE(VIA_REG_INTERRUPT, status);119119+120120+121121+ if (handled)122122+ return IRQ_HANDLED;123123+ else124124+ return IRQ_NONE;125125+}126126+127127+static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)128128+{129129+ u32 status;130130+131131+ if (dev_priv) {132132+ /* Acknowlege interrupts */133133+ status = VIA_READ(VIA_REG_INTERRUPT);134134+ VIA_WRITE(VIA_REG_INTERRUPT, status | 135135+ dev_priv->irq_pending_mask);136136+ }137137+}138138+139139+int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)140140+{141141+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;142142+ unsigned int cur_vblank;143143+ int ret = 0;144144+145145+ DRM_DEBUG("viadrv_vblank_wait\n");146146+ if (!dev_priv) {147147+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);148148+ return -EINVAL;149149+ }150150+151151+ viadrv_acknowledge_irqs(dev_priv);152152+153153+ /* Assume that the user has missed the current sequence number154154+ * by about a day rather than she wants to wait for years155155+ * using vertical blanks...156156+ */157157+158158+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,159159+ (((cur_vblank = atomic_read(&dev->vbl_received)) -160160+ *sequence) <= (1 << 23)));161161+162162+ *sequence = cur_vblank;163163+ return ret;164164+}165165+166166+static int 167167+via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,168168+ unsigned int *sequence)169169+{170170+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;171171+ unsigned int cur_irq_sequence;172172+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;173173+ int ret = 0;174174+ maskarray_t *masks = dev_priv->irq_masks;175175+176176+ DRM_DEBUG("%s\n", __FUNCTION__);177177+178178+ if (!dev_priv) {179179+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);180180+ return DRM_ERR(EINVAL);181181+ }182182+183183+ if (irq >= dev_priv->num_irqs ) {184184+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);185185+ return DRM_ERR(EINVAL);186186+ }187187+188188+ cur_irq += irq;189189+190190+ if (masks[irq][2] && !force_sequence) {191191+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,192192+ ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));193193+ cur_irq_sequence = atomic_read(&cur_irq->irq_received);194194+ } else {195195+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,196196+ (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -197197+ *sequence) <= (1 << 23))); 198198+ }199199+ *sequence = cur_irq_sequence;200200+ return ret;201201+}202202+203203+204204+/*205205+ * drm_dma.h hooks206206+ */207207+208208+void via_driver_irq_preinstall(drm_device_t * dev)209209+{210210+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;211211+ u32 status;212212+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;213213+ int i;214214+215215+ DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);216216+ if (dev_priv) {217217+218218+ dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;219219+ dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;220220+221221+ dev_priv->irq_masks = (dev_priv->pro_group_a) ?222222+ via_pro_group_a_irqs : via_unichrome_irqs;223223+ dev_priv->num_irqs = (dev_priv->pro_group_a) ?224224+ via_num_pro_group_a : via_num_unichrome;225225+226226+ for(i=0; i < dev_priv->num_irqs; ++i) {227227+ atomic_set(&cur_irq->irq_received, 0);228228+ cur_irq->enable_mask = dev_priv->irq_masks[i][0]; 229229+ cur_irq->pending_mask = dev_priv->irq_masks[i][1];230230+ DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );231231+ dev_priv->irq_enable_mask |= cur_irq->enable_mask;232232+ dev_priv->irq_pending_mask |= cur_irq->pending_mask;233233+ cur_irq++;234234+235235+ DRM_DEBUG("Initializing IRQ %d\n", i);236236+ }237237+238238+ dev_priv->last_vblank_valid = 0;239239+240240+ // Clear VSync interrupt regs241241+ status = VIA_READ(VIA_REG_INTERRUPT);242242+ VIA_WRITE(VIA_REG_INTERRUPT, status & 243243+ ~(dev_priv->irq_enable_mask));244244+245245+ /* Clear bits if they're already high */246246+ viadrv_acknowledge_irqs(dev_priv);247247+ }248248+}249249+250250+void via_driver_irq_postinstall(drm_device_t * dev)251251+{252252+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;253253+ u32 status;254254+255255+ DRM_DEBUG("via_driver_irq_postinstall\n");256256+ if (dev_priv) {257257+ status = VIA_READ(VIA_REG_INTERRUPT);258258+ VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL259259+ | dev_priv->irq_enable_mask);260260+261261+ /* Some magic, oh for some data sheets ! */262262+263263+ VIA_WRITE8(0x83d4, 0x11);264264+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);265265+266266+ }267267+}268268+269269+void via_driver_irq_uninstall(drm_device_t * dev)270270+{271271+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;272272+ u32 status;273273+274274+ DRM_DEBUG("driver_irq_uninstall)\n");275275+ if (dev_priv) {276276+277277+ /* Some more magic, oh for some data sheets ! */278278+279279+ VIA_WRITE8(0x83d4, 0x11);280280+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);281281+282282+ status = VIA_READ(VIA_REG_INTERRUPT);283283+ VIA_WRITE(VIA_REG_INTERRUPT, status & 284284+ ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));285285+ }286286+}287287+288288+int via_wait_irq(DRM_IOCTL_ARGS)289289+{290290+ drm_file_t *priv = filp->private_data;291291+ drm_device_t *dev = priv->head->dev;292292+ drm_via_irqwait_t __user *argp = (void __user *)data;293293+ drm_via_irqwait_t irqwait;294294+ struct timeval now;295295+ int ret = 0;296296+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;297297+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;298298+ int force_sequence;299299+300300+ if (!dev->irq)301301+ return DRM_ERR(EINVAL);302302+303303+ DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));304304+ if (irqwait.request.irq >= dev_priv->num_irqs) {305305+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, 306306+ irqwait.request.irq);307307+ return DRM_ERR(EINVAL);308308+ }309309+310310+ cur_irq += irqwait.request.irq;311311+312312+ switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {313313+ case VIA_IRQ_RELATIVE:314314+ irqwait.request.sequence += atomic_read(&cur_irq->irq_received);315315+ irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;316316+ case VIA_IRQ_ABSOLUTE:317317+ break;318318+ default:319319+ return DRM_ERR(EINVAL);320320+ }321321+322322+ if (irqwait.request.type & VIA_IRQ_SIGNAL) {323323+ DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n", 324324+ __FUNCTION__);325325+ return DRM_ERR(EINVAL);326326+ }327327+328328+ force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);329329+330330+ ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,331331+ &irqwait.request.sequence);332332+ do_gettimeofday(&now);333333+ irqwait.reply.tval_sec = now.tv_sec;334334+ irqwait.reply.tval_usec = now.tv_usec;335335+336336+ DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));337337+338338+ return ret;339339+}
+110
drivers/char/drm/via_map.c
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+#include "drmP.h"2525+#include "via_drm.h"2626+#include "via_drv.h"2727+2828+static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)2929+{3030+ drm_via_private_t *dev_priv;3131+3232+ DRM_DEBUG("%s\n", __FUNCTION__);3333+3434+ dev_priv = drm_alloc(sizeof(drm_via_private_t), DRM_MEM_DRIVER);3535+ if (dev_priv == NULL)3636+ return -ENOMEM;3737+3838+ memset(dev_priv, 0, sizeof(drm_via_private_t));3939+4040+ DRM_GETSAREA();4141+ if (!dev_priv->sarea) {4242+ DRM_ERROR("could not find sarea!\n");4343+ dev->dev_private = (void *)dev_priv;4444+ via_do_cleanup_map(dev);4545+ return -EINVAL;4646+ }4747+4848+ dev_priv->fb = drm_core_findmap(dev, init->fb_offset);4949+ if (!dev_priv->fb) {5050+ DRM_ERROR("could not find framebuffer!\n");5151+ dev->dev_private = (void *)dev_priv;5252+ via_do_cleanup_map(dev);5353+ return -EINVAL;5454+ }5555+ dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);5656+ if (!dev_priv->mmio) {5757+ DRM_ERROR("could not find mmio region!\n");5858+ dev->dev_private = (void *)dev_priv;5959+ via_do_cleanup_map(dev);6060+ return -EINVAL;6161+ }6262+6363+ dev_priv->sarea_priv =6464+ (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle +6565+ init->sarea_priv_offset);6666+6767+ dev_priv->agpAddr = init->agpAddr;6868+6969+ via_init_futex( dev_priv );7070+ dev_priv->pro_group_a = (dev->pdev->device == 0x3118);7171+7272+ dev->dev_private = (void *)dev_priv;7373+ return 0;7474+}7575+7676+int via_do_cleanup_map(drm_device_t * dev)7777+{7878+ if (dev->dev_private) {7979+8080+ drm_via_private_t *dev_priv = dev->dev_private;8181+8282+ via_dma_cleanup(dev);8383+8484+ drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);8585+ dev->dev_private = NULL;8686+ }8787+8888+ return 0;8989+}9090+9191+int via_map_init(DRM_IOCTL_ARGS)9292+{9393+ DRM_DEVICE;9494+ drm_via_init_t init;9595+9696+ DRM_DEBUG("%s\n", __FUNCTION__);9797+9898+ DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t *) data, sizeof(init));9999+100100+ switch (init.func) {101101+ case VIA_INIT_MAP:102102+ return via_do_init_map(dev, &init);103103+ case VIA_CLEANUP_MAP:104104+ return via_do_cleanup_map(dev);105105+ }106106+107107+ return -EINVAL;108108+}109109+110110+
+358
drivers/char/drm/via_mm.c
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+#include "drmP.h"2525+#include "via_drm.h"2626+#include "via_drv.h"2727+#include "via_ds.h"2828+#include "via_mm.h"2929+3030+#define MAX_CONTEXT 1003131+3232+typedef struct {3333+ int used;3434+ int context;3535+ set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */3636+} via_context_t;3737+3838+static via_context_t global_ppriv[MAX_CONTEXT];3939+4040+static int via_agp_alloc(drm_via_mem_t * mem);4141+static int via_agp_free(drm_via_mem_t * mem);4242+static int via_fb_alloc(drm_via_mem_t * mem);4343+static int via_fb_free(drm_via_mem_t * mem);4444+4545+static int add_alloc_set(int context, int type, unsigned int val)4646+{4747+ int i, retval = 0;4848+4949+ for (i = 0; i < MAX_CONTEXT; i++) {5050+ if (global_ppriv[i].used && global_ppriv[i].context == context) {5151+ retval = via_setAdd(global_ppriv[i].sets[type], val);5252+ break;5353+ }5454+ }5555+5656+ return retval;5757+}5858+5959+static int del_alloc_set(int context, int type, unsigned int val)6060+{6161+ int i, retval = 0;6262+6363+ for (i = 0; i < MAX_CONTEXT; i++)6464+ if (global_ppriv[i].used && global_ppriv[i].context == context) {6565+ retval = via_setDel(global_ppriv[i].sets[type], val);6666+ break;6767+ }6868+6969+ return retval;7070+}7171+7272+/* agp memory management */7373+static memHeap_t *AgpHeap = NULL;7474+7575+int via_agp_init(DRM_IOCTL_ARGS)7676+{7777+ drm_via_agp_t agp;7878+7979+ DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t *) data, sizeof(agp));8080+8181+ AgpHeap = via_mmInit(agp.offset, agp.size);8282+8383+ DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset, (unsigned long)agp.size);8484+8585+ return 0;8686+}8787+8888+/* fb memory management */8989+static memHeap_t *FBHeap = NULL;9090+9191+int via_fb_init(DRM_IOCTL_ARGS)9292+{9393+ drm_via_fb_t fb;9494+9595+ DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t *) data, sizeof(fb));9696+9797+ FBHeap = via_mmInit(fb.offset, fb.size);9898+9999+ DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset, (unsigned long)fb.size);100100+101101+ return 0;102102+}103103+104104+int via_init_context(struct drm_device *dev, int context)105105+{106106+ int i;107107+108108+ for (i = 0; i < MAX_CONTEXT; i++)109109+ if (global_ppriv[i].used &&110110+ (global_ppriv[i].context == context))111111+ break;112112+113113+ if (i >= MAX_CONTEXT) {114114+ for (i = 0; i < MAX_CONTEXT; i++) {115115+ if (!global_ppriv[i].used) {116116+ global_ppriv[i].context = context;117117+ global_ppriv[i].used = 1;118118+ global_ppriv[i].sets[0] = via_setInit();119119+ global_ppriv[i].sets[1] = via_setInit();120120+ DRM_DEBUG("init allocation set, socket=%d,"121121+ " context = %d\n", i, context);122122+ break;123123+ }124124+ }125125+126126+ if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||127127+ (global_ppriv[i].sets[1] == NULL)) {128128+ return 0;129129+ }130130+ }131131+132132+ return 1;133133+}134134+135135+int via_final_context(struct drm_device *dev, int context)136136+{ 137137+ int i;138138+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;139139+140140+ for (i = 0; i < MAX_CONTEXT; i++)141141+ if (global_ppriv[i].used &&142142+ (global_ppriv[i].context == context))143143+ break;144144+145145+ if (i < MAX_CONTEXT) {146146+ set_t *set;147147+ ITEM_TYPE item;148148+ int retval;149149+150150+ DRM_DEBUG("find socket %d, context = %d\n", i, context);151151+152152+ /* Video Memory */153153+ set = global_ppriv[i].sets[0];154154+ retval = via_setFirst(set, &item);155155+ while (retval) {156156+ DRM_DEBUG("free video memory 0x%lx\n", item);157157+ via_mmFreeMem((PMemBlock) item);158158+ retval = via_setNext(set, &item);159159+ }160160+ via_setDestroy(set);161161+162162+ /* AGP Memory */163163+ set = global_ppriv[i].sets[1];164164+ retval = via_setFirst(set, &item);165165+ while (retval) {166166+ DRM_DEBUG("free agp memory 0x%lx\n", item);167167+ via_mmFreeMem((PMemBlock) item);168168+ retval = via_setNext(set, &item);169169+ }170170+ via_setDestroy(set);171171+ global_ppriv[i].used = 0;172172+ }173173+ via_release_futex(dev_priv, context); 174174+175175+176176+#if defined(__linux__)177177+ /* Linux specific until context tracking code gets ported to BSD */178178+ /* Last context, perform cleanup */179179+ if (dev->ctx_count == 1 && dev->dev_private) {180180+ DRM_DEBUG("Last Context\n");181181+ if (dev->irq)182182+ drm_irq_uninstall(dev);183183+184184+ via_cleanup_futex(dev_priv);185185+ via_do_cleanup_map(dev);186186+ }187187+#endif188188+189189+ return 1;190190+}191191+192192+int via_mem_alloc(DRM_IOCTL_ARGS)193193+{194194+ drm_via_mem_t mem;195195+196196+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));197197+198198+ switch (mem.type) {199199+ case VIDEO:200200+ if (via_fb_alloc(&mem) < 0)201201+ return -EFAULT;202202+ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,203203+ sizeof(mem));204204+ return 0;205205+ case AGP:206206+ if (via_agp_alloc(&mem) < 0)207207+ return -EFAULT;208208+ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,209209+ sizeof(mem));210210+ return 0;211211+ }212212+213213+ return -EFAULT;214214+}215215+216216+static int via_fb_alloc(drm_via_mem_t * mem)217217+{218218+ drm_via_mm_t fb;219219+ PMemBlock block;220220+ int retval = 0;221221+222222+ if (!FBHeap)223223+ return -1;224224+225225+ fb.size = mem->size;226226+ fb.context = mem->context;227227+228228+ block = via_mmAllocMem(FBHeap, fb.size, 5, 0);229229+ if (block) {230230+ fb.offset = block->ofs;231231+ fb.free = (unsigned long)block;232232+ if (!add_alloc_set(fb.context, VIDEO, fb.free)) {233233+ DRM_DEBUG("adding to allocation set fails\n");234234+ via_mmFreeMem((PMemBlock) fb.free);235235+ retval = -1;236236+ }237237+ } else {238238+ fb.offset = 0;239239+ fb.size = 0;240240+ fb.free = 0;241241+ retval = -1;242242+ }243243+244244+ mem->offset = fb.offset;245245+ mem->index = fb.free;246246+247247+ DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,248248+ (int)fb.offset);249249+250250+ return retval;251251+}252252+253253+static int via_agp_alloc(drm_via_mem_t * mem)254254+{255255+ drm_via_mm_t agp;256256+ PMemBlock block;257257+ int retval = 0;258258+259259+ if (!AgpHeap)260260+ return -1;261261+262262+ agp.size = mem->size;263263+ agp.context = mem->context;264264+265265+ block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);266266+ if (block) {267267+ agp.offset = block->ofs;268268+ agp.free = (unsigned long)block;269269+ if (!add_alloc_set(agp.context, AGP, agp.free)) {270270+ DRM_DEBUG("adding to allocation set fails\n");271271+ via_mmFreeMem((PMemBlock) agp.free);272272+ retval = -1;273273+ }274274+ } else {275275+ agp.offset = 0;276276+ agp.size = 0;277277+ agp.free = 0;278278+ }279279+280280+ mem->offset = agp.offset;281281+ mem->index = agp.free;282282+283283+ DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,284284+ (unsigned int)agp.offset);285285+ return retval;286286+}287287+288288+int via_mem_free(DRM_IOCTL_ARGS)289289+{290290+ drm_via_mem_t mem;291291+292292+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));293293+294294+ switch (mem.type) {295295+296296+ case VIDEO:297297+ if (via_fb_free(&mem) == 0)298298+ return 0;299299+ break;300300+ case AGP:301301+ if (via_agp_free(&mem) == 0)302302+ return 0;303303+ break;304304+ }305305+306306+ return -EFAULT;307307+}308308+309309+static int via_fb_free(drm_via_mem_t * mem)310310+{311311+ drm_via_mm_t fb;312312+ int retval = 0;313313+314314+ if (!FBHeap) {315315+ return -1;316316+ }317317+318318+ fb.free = mem->index;319319+ fb.context = mem->context;320320+321321+ if (!fb.free) {322322+ return -1;323323+324324+ }325325+326326+ via_mmFreeMem((PMemBlock) fb.free);327327+328328+ if (!del_alloc_set(fb.context, VIDEO, fb.free)) {329329+ retval = -1;330330+ }331331+332332+ DRM_DEBUG("free fb, free = %ld\n", fb.free);333333+334334+ return retval;335335+}336336+337337+static int via_agp_free(drm_via_mem_t * mem)338338+{339339+ drm_via_mm_t agp;340340+341341+ int retval = 0;342342+343343+ agp.free = mem->index;344344+ agp.context = mem->context;345345+346346+ if (!agp.free)347347+ return -1;348348+349349+ via_mmFreeMem((PMemBlock) agp.free);350350+351351+ if (!del_alloc_set(agp.context, AGP, agp.free)) {352352+ retval = -1;353353+ }354354+355355+ DRM_DEBUG("free agp, free = %ld\n", agp.free);356356+357357+ return retval;358358+}
+40
drivers/char/drm/via_mm.h
···11+/*22+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.33+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ */2424+#ifndef _via_drm_mm_h_2525+#define _via_drm_mm_h_2626+2727+typedef struct {2828+ unsigned int context;2929+ unsigned int size;3030+ unsigned long offset;3131+ unsigned long free;3232+} drm_via_mm_t;3333+3434+typedef struct {3535+ unsigned int size;3636+ unsigned long handle;3737+ void *virtual;3838+} drm_via_dma_t;3939+4040+#endif
+1061
drivers/char/drm/via_verifier.c
···11+/*22+ * Copyright 2004 The Unichrome Project. All Rights Reserved.33+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.44+ *55+ * Permission is hereby granted, free of charge, to any person obtaining a66+ * copy of this software and associated documentation files (the "Software"),77+ * to deal in the Software without restriction, including without limitation88+ * the rights to use, copy, modify, merge, publish, distribute, sub license,99+ * and/or sell copies of the Software, and to permit persons to whom the1010+ * Software is furnished to do so, subject to the following conditions:1111+ *1212+ * The above copyright notice and this permission notice (including the1313+ * next paragraph) shall be included in all copies or substantial portions1414+ * of the Software.1515+ *1616+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1717+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1818+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1919+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR2020+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2121+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2222+ * DEALINGS IN THE SOFTWARE.2323+ *2424+ * Author: Thomas Hellstrom 2004, 2005.2525+ * This code was written using docs obtained under NDA from VIA Inc.2626+ *2727+ * Don't run this code directly on an AGP buffer. Due to cache problems it will2828+ * be very slow.2929+ */3030+3131+3232+#include "via_3d_reg.h"3333+#include "drmP.h"3434+#include "drm.h"3535+#include "via_drm.h"3636+#include "via_verifier.h"3737+#include "via_drv.h"3838+3939+typedef enum{4040+ state_command,4141+ state_header2,4242+ state_header1,4343+ state_vheader5,4444+ state_vheader6,4545+ state_error4646+} verifier_state_t;4747+4848+4949+typedef enum{5050+ no_check = 0,5151+ check_for_header2,5252+ check_for_header1,5353+ check_for_header2_err,5454+ check_for_header1_err,5555+ check_for_fire,5656+ check_z_buffer_addr0,5757+ check_z_buffer_addr1,5858+ check_z_buffer_addr_mode,5959+ check_destination_addr0,6060+ check_destination_addr1,6161+ check_destination_addr_mode,6262+ check_for_dummy,6363+ check_for_dd,6464+ check_texture_addr0,6565+ check_texture_addr1,6666+ check_texture_addr2,6767+ check_texture_addr3,6868+ check_texture_addr4,6969+ check_texture_addr5,7070+ check_texture_addr6,7171+ check_texture_addr7,7272+ check_texture_addr8,7373+ check_texture_addr_mode,7474+ check_for_vertex_count,7575+ check_number_texunits,7676+ forbidden_command7777+}hazard_t;7878+7979+/*8080+ * Associates each hazard above with a possible multi-command8181+ * sequence. For example an address that is split over multiple8282+ * commands and that needs to be checked at the first command 8383+ * that does not include any part of the address.8484+ */8585+8686+static drm_via_sequence_t seqs[] = { 8787+ no_sequence,8888+ no_sequence,8989+ no_sequence,9090+ no_sequence,9191+ no_sequence,9292+ no_sequence,9393+ z_address,9494+ z_address,9595+ z_address,9696+ dest_address,9797+ dest_address,9898+ dest_address,9999+ no_sequence,100100+ no_sequence,101101+ tex_address,102102+ tex_address,103103+ tex_address,104104+ tex_address,105105+ tex_address,106106+ tex_address,107107+ tex_address,108108+ tex_address,109109+ tex_address,110110+ tex_address,111111+ no_sequence112112+};113113+114114+typedef struct{115115+ unsigned int code;116116+ hazard_t hz;117117+} hz_init_t;118118+119119+120120+121121+static hz_init_t init_table1[] = {122122+ {0xf2, check_for_header2_err},123123+ {0xf0, check_for_header1_err},124124+ {0xee, check_for_fire},125125+ {0xcc, check_for_dummy},126126+ {0xdd, check_for_dd},127127+ {0x00, no_check},128128+ {0x10, check_z_buffer_addr0},129129+ {0x11, check_z_buffer_addr1},130130+ {0x12, check_z_buffer_addr_mode},131131+ {0x13, no_check},132132+ {0x14, no_check},133133+ {0x15, no_check},134134+ {0x23, no_check},135135+ {0x24, no_check},136136+ {0x33, no_check},137137+ {0x34, no_check},138138+ {0x35, no_check},139139+ {0x36, no_check},140140+ {0x37, no_check},141141+ {0x38, no_check},142142+ {0x39, no_check},143143+ {0x3A, no_check},144144+ {0x3B, no_check},145145+ {0x3C, no_check},146146+ {0x3D, no_check},147147+ {0x3E, no_check},148148+ {0x40, check_destination_addr0},149149+ {0x41, check_destination_addr1},150150+ {0x42, check_destination_addr_mode},151151+ {0x43, no_check},152152+ {0x44, no_check},153153+ {0x50, no_check},154154+ {0x51, no_check},155155+ {0x52, no_check},156156+ {0x53, no_check},157157+ {0x54, no_check},158158+ {0x55, no_check},159159+ {0x56, no_check},160160+ {0x57, no_check},161161+ {0x58, no_check},162162+ {0x70, no_check},163163+ {0x71, no_check},164164+ {0x78, no_check},165165+ {0x79, no_check},166166+ {0x7A, no_check},167167+ {0x7B, no_check},168168+ {0x7C, no_check},169169+ {0x7D, check_for_vertex_count}170170+};171171+172172+173173+174174+static hz_init_t init_table2[] = {175175+ {0xf2, check_for_header2_err},176176+ {0xf0, check_for_header1_err},177177+ {0xee, check_for_fire},178178+ {0xcc, check_for_dummy},179179+ {0x00, check_texture_addr0},180180+ {0x01, check_texture_addr0},181181+ {0x02, check_texture_addr0},182182+ {0x03, check_texture_addr0},183183+ {0x04, check_texture_addr0},184184+ {0x05, check_texture_addr0},185185+ {0x06, check_texture_addr0},186186+ {0x07, check_texture_addr0},187187+ {0x08, check_texture_addr0},188188+ {0x09, check_texture_addr0},189189+ {0x20, check_texture_addr1},190190+ {0x21, check_texture_addr1},191191+ {0x22, check_texture_addr1},192192+ {0x23, check_texture_addr4},193193+ {0x2B, check_texture_addr3},194194+ {0x2C, check_texture_addr3},195195+ {0x2D, check_texture_addr3},196196+ {0x2E, check_texture_addr3},197197+ {0x2F, check_texture_addr3},198198+ {0x30, check_texture_addr3},199199+ {0x31, check_texture_addr3},200200+ {0x32, check_texture_addr3},201201+ {0x33, check_texture_addr3},202202+ {0x34, check_texture_addr3},203203+ {0x4B, check_texture_addr5},204204+ {0x4C, check_texture_addr6},205205+ {0x51, check_texture_addr7},206206+ {0x52, check_texture_addr8},207207+ {0x77, check_texture_addr2},208208+ {0x78, no_check},209209+ {0x79, no_check},210210+ {0x7A, no_check},211211+ {0x7B, check_texture_addr_mode},212212+ {0x7C, no_check},213213+ {0x7D, no_check},214214+ {0x7E, no_check},215215+ {0x7F, no_check},216216+ {0x80, no_check},217217+ {0x81, no_check},218218+ {0x82, no_check},219219+ {0x83, no_check},220220+ {0x85, no_check},221221+ {0x86, no_check},222222+ {0x87, no_check},223223+ {0x88, no_check},224224+ {0x89, no_check},225225+ {0x8A, no_check},226226+ {0x90, no_check},227227+ {0x91, no_check},228228+ {0x92, no_check},229229+ {0x93, no_check}230230+};231231+232232+static hz_init_t init_table3[] = {233233+ {0xf2, check_for_header2_err},234234+ {0xf0, check_for_header1_err},235235+ {0xcc, check_for_dummy},236236+ {0x00, check_number_texunits}237237+};238238+239239+240240+static hazard_t table1[256]; 241241+static hazard_t table2[256]; 242242+static hazard_t table3[256]; 243243+244244+245245+246246+static __inline__ int247247+eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)248248+{249249+ if ((*buf - buf_end) >= num_words) {250250+ *buf += num_words;251251+ return 0;252252+ } 253253+ DRM_ERROR("Illegal termination of DMA command buffer\n");254254+ return 1;255255+}256256+257257+258258+/*259259+ * Partially stolen from drm_memory.h260260+ */261261+262262+static __inline__ drm_map_t *263263+via_drm_lookup_agp_map (drm_via_state_t *seq, unsigned long offset, unsigned long size, 264264+ drm_device_t *dev)265265+{266266+ struct list_head *list;267267+ drm_map_list_t *r_list;268268+ drm_map_t *map = seq->map_cache;269269+270270+ if (map && map->offset <= offset && (offset + size) <= (map->offset + map->size)) {271271+ return map;272272+ }273273+274274+ list_for_each(list, &dev->maplist->head) {275275+ r_list = (drm_map_list_t *) list;276276+ map = r_list->map;277277+ if (!map)278278+ continue;279279+ if (map->offset <= offset && (offset + size) <= (map->offset + map->size) && 280280+ !(map->flags & _DRM_RESTRICTED) && (map->type == _DRM_AGP)) {281281+ seq->map_cache = map;282282+ return map;283283+ }284284+ }285285+ return NULL;286286+}287287+288288+289289+/*290290+ * Require that all AGP texture levels reside in the same AGP map which should 291291+ * be mappable by the client. This is not a big restriction.292292+ * FIXME: To actually enforce this security policy strictly, drm_rmmap 293293+ * would have to wait for dma quiescent before removing an AGP map. 294294+ * The via_drm_lookup_agp_map call in reality seems to take295295+ * very little CPU time.296296+ */297297+298298+299299+static __inline__ int300300+finish_current_sequence(drm_via_state_t *cur_seq) 301301+{302302+ switch(cur_seq->unfinished) {303303+ case z_address:304304+ DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);305305+ break;306306+ case dest_address:307307+ DRM_DEBUG("Destination start address is 0x%x\n", cur_seq->d_addr);308308+ break;309309+ case tex_address:310310+ if (cur_seq->agp_texture) { 311311+ unsigned start = cur_seq->tex_level_lo[cur_seq->texture];312312+ unsigned end = cur_seq->tex_level_hi[cur_seq->texture];313313+ unsigned long lo=~0, hi=0, tmp;314314+ uint32_t *addr, *pitch, *height, tex;315315+ unsigned i;316316+317317+ if (end > 9) end = 9;318318+ if (start > 9) start = 9;319319+320320+ addr =&(cur_seq->t_addr[tex = cur_seq->texture][start]);321321+ pitch = &(cur_seq->pitch[tex][start]);322322+ height = &(cur_seq->height[tex][start]);323323+324324+ for (i=start; i<= end; ++i) {325325+ tmp = *addr++;326326+ if (tmp < lo) lo = tmp;327327+ tmp += (*height++ << *pitch++);328328+ if (tmp > hi) hi = tmp;329329+ }330330+331331+ if (! via_drm_lookup_agp_map (cur_seq, lo, hi - lo, cur_seq->dev)) {332332+ DRM_ERROR("AGP texture is not in allowed map\n");333333+ return 2;334334+ }335335+ } 336336+ break;337337+ default:338338+ break;339339+ }340340+ cur_seq->unfinished = no_sequence;341341+ return 0;342342+}343343+344344+static __inline__ int 345345+investigate_hazard( uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)346346+{347347+ register uint32_t tmp, *tmp_addr;348348+349349+ if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {350350+ int ret;351351+ if ((ret = finish_current_sequence(cur_seq))) return ret;352352+ }353353+354354+ switch(hz) {355355+ case check_for_header2:356356+ if (cmd == HALCYON_HEADER2) return 1;357357+ return 0;358358+ case check_for_header1:359359+ if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;360360+ return 0;361361+ case check_for_header2_err:362362+ if (cmd == HALCYON_HEADER2) return 1;363363+ DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");364364+ break;365365+ case check_for_header1_err:366366+ if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;367367+ DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");368368+ break;369369+ case check_for_fire:370370+ if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) return 1; 371371+ DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");372372+ break;373373+ case check_for_dummy:374374+ if (HC_DUMMY == cmd) return 0;375375+ DRM_ERROR("Illegal DMA HC_DUMMY command\n");376376+ break;377377+ case check_for_dd:378378+ if (0xdddddddd == cmd) return 0;379379+ DRM_ERROR("Illegal DMA 0xdddddddd command\n");380380+ break;381381+ case check_z_buffer_addr0:382382+ cur_seq->unfinished = z_address;383383+ cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |384384+ (cmd & 0x00FFFFFF);385385+ return 0;386386+ case check_z_buffer_addr1:387387+ cur_seq->unfinished = z_address;388388+ cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |389389+ ((cmd & 0xFF) << 24);390390+ return 0;391391+ case check_z_buffer_addr_mode:392392+ cur_seq->unfinished = z_address;393393+ if ((cmd & 0x0000C000) == 0) return 0;394394+ DRM_ERROR("Attempt to place Z buffer in system memory\n");395395+ return 2;396396+ case check_destination_addr0:397397+ cur_seq->unfinished = dest_address;398398+ cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |399399+ (cmd & 0x00FFFFFF);400400+ return 0;401401+ case check_destination_addr1:402402+ cur_seq->unfinished = dest_address;403403+ cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |404404+ ((cmd & 0xFF) << 24);405405+ return 0;406406+ case check_destination_addr_mode:407407+ cur_seq->unfinished = dest_address;408408+ if ((cmd & 0x0000C000) == 0) return 0;409409+ DRM_ERROR("Attempt to place 3D drawing buffer in system memory\n");410410+ return 2; 411411+ case check_texture_addr0:412412+ cur_seq->unfinished = tex_address;413413+ tmp = (cmd >> 24);414414+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];415415+ *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);416416+ return 0;417417+ case check_texture_addr1:418418+ cur_seq->unfinished = tex_address;419419+ tmp = ((cmd >> 24) - 0x20);420420+ tmp += tmp << 1;421421+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];422422+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);423423+ tmp_addr++;424424+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);425425+ tmp_addr++;426426+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);427427+ return 0;428428+ case check_texture_addr2:429429+ cur_seq->unfinished = tex_address;430430+ cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;431431+ cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;432432+ return 0;433433+ case check_texture_addr3:434434+ cur_seq->unfinished = tex_address;435435+ tmp = ((cmd >> 24) - 0x2B);436436+ cur_seq->pitch[cur_seq->texture][tmp] = (cmd & 0x00F00000) >> 20;437437+ if (!tmp && (cmd & 0x000FFFFF)) {438438+ DRM_ERROR("Unimplemented texture level 0 pitch mode.\n");439439+ return 2;440440+ }441441+ return 0;442442+ case check_texture_addr4:443443+ cur_seq->unfinished = tex_address;444444+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];445445+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);446446+ return 0;447447+ case check_texture_addr5:448448+ case check_texture_addr6:449449+ cur_seq->unfinished = tex_address;450450+ /*451451+ * Texture width. We don't care since we have the pitch.452452+ */ 453453+ return 0;454454+ case check_texture_addr7:455455+ cur_seq->unfinished = tex_address;456456+ tmp_addr = &(cur_seq->height[cur_seq->texture][0]);457457+ tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);458458+ tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);459459+ tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);460460+ tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);461461+ tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);462462+ tmp_addr[0] = 1 << (cmd & 0x0000000F);463463+ return 0;464464+ case check_texture_addr8:465465+ cur_seq->unfinished = tex_address;466466+ tmp_addr = &(cur_seq->height[cur_seq->texture][0]);467467+ tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);468468+ tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);469469+ tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);470470+ tmp_addr[6] = 1 << (cmd & 0x0000000F);471471+ return 0;472472+ case check_texture_addr_mode:473473+ cur_seq->unfinished = tex_address;474474+ if ( 2 == (tmp = cmd & 0x00000003)) {475475+ DRM_ERROR("Attempt to fetch texture from system memory.\n"); 476476+ return 2;477477+ }478478+ cur_seq->agp_texture = (tmp == 3);479479+ cur_seq->tex_palette_size[cur_seq->texture] = 480480+ (cmd >> 16) & 0x000000007;481481+ return 0;482482+ case check_for_vertex_count:483483+ cur_seq->vertex_count = cmd & 0x0000FFFF;484484+ return 0;485485+ case check_number_texunits:486486+ cur_seq->multitex = (cmd >> 3) & 1;487487+ return 0;488488+ default:489489+ DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);490490+ return 2;491491+ }492492+ return 2;493493+}494494+495495+496496+static __inline__ int497497+via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,498498+ drm_via_state_t *cur_seq)499499+{500500+ drm_via_private_t *dev_priv = (drm_via_private_t *) cur_seq->dev->dev_private;501501+ uint32_t a_fire, bcmd , dw_count;502502+ int ret = 0;503503+ int have_fire;504504+ const uint32_t *buf = *buffer;505505+506506+ while(buf < buf_end) {507507+ have_fire = 0;508508+ if ((buf_end - buf) < 2) {509509+ DRM_ERROR("Unexpected termination of primitive list.\n");510510+ ret = 1;511511+ break;512512+ }513513+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;514514+ bcmd = *buf++;515515+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {516516+ DRM_ERROR("Expected Vertex List A command, got 0x%x\n",517517+ *buf);518518+ ret = 1;519519+ break;520520+ }521521+ a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK; 522522+523523+ /*524524+ * How many dwords per vertex ?525525+ */ 526526+527527+ if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {528528+ DRM_ERROR("Illegal B command vertex data for AGP.\n");529529+ ret = 1;530530+ break;531531+ } 532532+533533+ dw_count = 0;534534+ if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;535535+ if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;536536+ if (bcmd & (1 << 9)) dw_count++;537537+ if (bcmd & (1 << 10)) dw_count++;538538+ if (bcmd & (1 << 11)) dw_count++;539539+ if (bcmd & (1 << 12)) dw_count++;540540+ if (bcmd & (1 << 13)) dw_count++;541541+ if (bcmd & (1 << 14)) dw_count++;542542+543543+ while(buf < buf_end) {544544+ if (*buf == a_fire) {545545+ if (dev_priv->num_fire_offsets >= VIA_FIRE_BUF_SIZE) {546546+ DRM_ERROR("Fire offset buffer full.\n");547547+ ret = 1;548548+ break;549549+ }550550+ dev_priv->fire_offsets[dev_priv->num_fire_offsets++] = buf;551551+ have_fire = 1;552552+ buf++;553553+ if (buf < buf_end && *buf == a_fire) 554554+ buf++;555555+ break;556556+ }557557+ if ((*buf == HALCYON_HEADER2) || 558558+ ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {559559+ DRM_ERROR("Missing Vertex Fire command, "560560+ "Stray Vertex Fire command or verifier "561561+ "lost sync.\n");562562+ ret = 1;563563+ break;564564+ }565565+ if ((ret = eat_words(&buf, buf_end, dw_count)))566566+ break;567567+ }568568+ if (buf >= buf_end && !have_fire) {569569+ DRM_ERROR("Missing Vertex Fire command or verifier "570570+ "lost sync.\n");571571+ ret = 1;572572+ break;573573+ }574574+ if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {575575+ DRM_ERROR("AGP Primitive list end misaligned.\n");576576+ ret = 1;577577+ break;578578+ }579579+ } 580580+ *buffer = buf;581581+ return ret;582582+}583583+584584+585585+586586+587587+588588+static __inline__ verifier_state_t589589+via_check_header2( uint32_t const **buffer, const uint32_t *buf_end, 590590+ drm_via_state_t *hc_state)591591+{592592+ uint32_t cmd;593593+ int hz_mode;594594+ hazard_t hz;595595+ const uint32_t *buf = *buffer;596596+ const hazard_t *hz_table;597597+598598+599599+ if ((buf_end - buf) < 2) {600600+ DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");601601+ return state_error;602602+ }603603+ buf++;604604+ cmd = (*buf++ & 0xFFFF0000) >> 16;605605+606606+ switch(cmd) {607607+ case HC_ParaType_CmdVdata:608608+ if (via_check_prim_list(&buf, buf_end, hc_state )) 609609+ return state_error;610610+ *buffer = buf;611611+ return state_command;612612+ case HC_ParaType_NotTex:613613+ hz_table = table1;614614+ break;615615+ case HC_ParaType_Tex:616616+ hc_state->texture = 0;617617+ hz_table = table2;618618+ break;619619+ case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):620620+ hc_state->texture = 1;621621+ hz_table = table2;622622+ break;623623+ case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):624624+ hz_table = table3;625625+ break;626626+ case HC_ParaType_Auto:627627+ if (eat_words(&buf, buf_end, 2))628628+ return state_error;629629+ *buffer = buf;630630+ return state_command;631631+ case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):632632+ if (eat_words(&buf, buf_end, 32))633633+ return state_error;634634+ *buffer = buf;635635+ return state_command;636636+ case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):637637+ case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):638638+ DRM_ERROR("Texture palettes are rejected because of "639639+ "lack of info how to determine their size.\n");640640+ return state_error;641641+ case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):642642+ DRM_ERROR("Fog factor palettes are rejected because of "643643+ "lack of info how to determine their size.\n");644644+ return state_error;645645+ default:646646+647647+ /*648648+ * There are some unimplemented HC_ParaTypes here, that649649+ * need to be implemented if the Mesa driver is extended.650650+ */651651+652652+ DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "653653+ "DMA subcommand: 0x%x. Previous dword: 0x%x\n", 654654+ cmd, *(buf -2));655655+ *buffer = buf;656656+ return state_error;657657+ }658658+659659+ while(buf < buf_end) {660660+ cmd = *buf++;661661+ if ((hz = hz_table[cmd >> 24])) {662662+ if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {663663+ if (hz_mode == 1) {664664+ buf--;665665+ break;666666+ }667667+ return state_error;668668+ }669669+ } else if (hc_state->unfinished && 670670+ finish_current_sequence(hc_state)) {671671+ return state_error;672672+ }673673+ }674674+ if (hc_state->unfinished && finish_current_sequence(hc_state)) {675675+ return state_error;676676+ }677677+ *buffer = buf;678678+ return state_command;679679+}680680+681681+static __inline__ verifier_state_t682682+via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end,683683+ int *fire_count)684684+{685685+ uint32_t cmd;686686+ const uint32_t *buf = *buffer;687687+ const uint32_t *next_fire; 688688+ int burst = 0;689689+690690+ next_fire = dev_priv->fire_offsets[*fire_count];691691+ buf++;692692+ cmd = (*buf & 0xFFFF0000) >> 16;693693+ VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);694694+ switch(cmd) {695695+ case HC_ParaType_CmdVdata:696696+ while ((buf < buf_end) &&697697+ (*fire_count < dev_priv->num_fire_offsets) && 698698+ (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) {699699+ while(buf <= next_fire) {700700+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);701701+ burst += 4;702702+ }703703+ if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))704704+ buf++;705705+706706+ if (++(*fire_count) < dev_priv->num_fire_offsets) 707707+ next_fire = dev_priv->fire_offsets[*fire_count];708708+ }709709+ break;710710+ default:711711+ while(buf < buf_end) {712712+713713+ if ( *buf == HC_HEADER2 ||714714+ (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||715715+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||716716+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break;717717+718718+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);719719+ burst +=4;720720+ }721721+ }722722+ *buffer = buf;723723+ return state_command;724724+}725725+726726+727727+728728+static __inline__ int729729+verify_mmio_address( uint32_t address)730730+{731731+ if ((address > 0x3FF) && (address < 0xC00 )) {732732+ DRM_ERROR("Invalid VIDEO DMA command. "733733+ "Attempt to access 3D- or command burst area.\n");734734+ return 1;735735+ } else if ((address > 0xCFF) && (address < 0x1300)) {736736+ DRM_ERROR("Invalid VIDEO DMA command. "737737+ "Attempt to access PCI DMA area.\n");738738+ return 1; 739739+ } else if (address > 0x13FF ) {740740+ DRM_ERROR("Invalid VIDEO DMA command. "741741+ "Attempt to access VGA registers.\n");742742+ return 1;743743+ }744744+ return 0;745745+}746746+747747+static __inline__ int748748+verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords) 749749+{750750+ const uint32_t *buf = *buffer;751751+752752+ if (buf_end - buf < dwords) {753753+ DRM_ERROR("Illegal termination of video command.\n");754754+ return 1;755755+ }756756+ while (dwords--) {757757+ if (*buf++) {758758+ DRM_ERROR("Illegal video command tail.\n");759759+ return 1;760760+ }761761+ }762762+ *buffer = buf;763763+ return 0;764764+}765765+766766+767767+static __inline__ verifier_state_t768768+via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )769769+{770770+ uint32_t cmd;771771+ const uint32_t *buf = *buffer;772772+ verifier_state_t ret = state_command;773773+774774+ while (buf < buf_end) {775775+ cmd = *buf;776776+ if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&777777+ (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { 778778+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 779779+ break;780780+ DRM_ERROR("Invalid HALCYON_HEADER1 command. "781781+ "Attempt to access 3D- or command burst area.\n");782782+ ret = state_error;783783+ break;784784+ } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {785785+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 786786+ break;787787+ DRM_ERROR("Invalid HALCYON_HEADER1 command. "788788+ "Attempt to access VGA registers.\n");789789+ ret = state_error;790790+ break; 791791+ } else { 792792+ buf += 2;793793+ }794794+ }795795+ *buffer = buf;796796+ return ret;797797+}798798+799799+static __inline__ verifier_state_t800800+via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )801801+{802802+ register uint32_t cmd;803803+ const uint32_t *buf = *buffer;804804+805805+ while (buf < buf_end) {806806+ cmd = *buf;807807+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break;808808+ VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); 809809+ buf++;810810+ }811811+ *buffer = buf;812812+ return state_command;813813+}814814+815815+static __inline__ verifier_state_t816816+via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )817817+{818818+ uint32_t data;819819+ const uint32_t *buf = *buffer;820820+821821+ if (buf_end - buf < 4) {822822+ DRM_ERROR("Illegal termination of video header5 command\n");823823+ return state_error;824824+ }825825+826826+ data = *buf++ & ~VIA_VIDEOMASK;827827+ if (verify_mmio_address(data))828828+ return state_error;829829+830830+ data = *buf++;831831+ if (*buf++ != 0x00F50000) {832832+ DRM_ERROR("Illegal header5 header data\n");833833+ return state_error;834834+ }835835+ if (*buf++ != 0x00000000) {836836+ DRM_ERROR("Illegal header5 header data\n");837837+ return state_error;838838+ }839839+ if (eat_words(&buf, buf_end, data)) 840840+ return state_error;841841+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 842842+ return state_error;843843+ *buffer = buf;844844+ return state_command;845845+846846+} 847847+848848+static __inline__ verifier_state_t849849+via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )850850+{851851+ uint32_t addr, count, i;852852+ const uint32_t *buf = *buffer;853853+854854+ addr = *buf++ & ~VIA_VIDEOMASK;855855+ i = count = *buf;856856+ buf += 3;857857+ while(i--) {858858+ VIA_WRITE(addr, *buf++);859859+ }860860+ if (count & 3) buf += 4 - (count & 3);861861+ *buffer = buf;862862+ return state_command; 863863+} 864864+865865+866866+static __inline__ verifier_state_t867867+via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )868868+{869869+ uint32_t data;870870+ const uint32_t *buf = *buffer;871871+ uint32_t i;872872+873873+874874+ if (buf_end - buf < 4) {875875+ DRM_ERROR("Illegal termination of video header6 command\n");876876+ return state_error;877877+ }878878+ buf++;879879+ data = *buf++;880880+ if (*buf++ != 0x00F60000) {881881+ DRM_ERROR("Illegal header6 header data\n");882882+ return state_error;883883+ }884884+ if (*buf++ != 0x00000000) {885885+ DRM_ERROR("Illegal header6 header data\n");886886+ return state_error;887887+ }888888+ if ((buf_end - buf) < (data << 1)) {889889+ DRM_ERROR("Illegal termination of video header6 command\n");890890+ return state_error;891891+ }892892+ for (i=0; i<data; ++i) {893893+ if (verify_mmio_address(*buf++))894894+ return state_error;895895+ buf++;896896+ }897897+ data <<= 1;898898+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))899899+ return state_error;900900+ *buffer = buf;901901+ return state_command;902902+} 903903+904904+static __inline__ verifier_state_t905905+via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )906906+{907907+908908+ uint32_t addr, count, i;909909+ const uint32_t *buf = *buffer;910910+911911+ i = count = *++buf;912912+ buf += 3;913913+ while(i--) {914914+ addr = *buf++;915915+ VIA_WRITE(addr, *buf++);916916+ }917917+ count <<= 1;918918+ if (count & 3) buf += 4 - (count & 3);919919+ *buffer = buf;920920+ return state_command;921921+} 922922+923923+924924+925925+int 926926+via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev,927927+ int agp)928928+{929929+930930+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;931931+ drm_via_state_t *hc_state = &dev_priv->hc_state;932932+ drm_via_state_t saved_state = *hc_state;933933+ uint32_t cmd;934934+ const uint32_t *buf_end = buf + ( size >> 2 );935935+ verifier_state_t state = state_command;936936+ int pro_group_a = dev_priv->pro_group_a;937937+938938+ hc_state->dev = dev;939939+ hc_state->unfinished = no_sequence;940940+ hc_state->map_cache = NULL;941941+ hc_state->agp = agp;942942+ hc_state->buf_start = buf;943943+ dev_priv->num_fire_offsets = 0;944944+945945+ while (buf < buf_end) {946946+947947+ switch (state) {948948+ case state_header2:949949+ state = via_check_header2( &buf, buf_end, hc_state );950950+ break;951951+ case state_header1:952952+ state = via_check_header1( &buf, buf_end );953953+ break;954954+ case state_vheader5:955955+ state = via_check_vheader5( &buf, buf_end );956956+ break;957957+ case state_vheader6:958958+ state = via_check_vheader6( &buf, buf_end );959959+ break;960960+ case state_command:961961+ if (HALCYON_HEADER2 == (cmd = *buf)) 962962+ state = state_header2;963963+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 964964+ state = state_header1;965965+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)966966+ state = state_vheader5;967967+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)968968+ state = state_vheader6;969969+ else {970970+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",971971+ cmd);972972+ state = state_error;973973+ }974974+ break;975975+ case state_error:976976+ default:977977+ *hc_state = saved_state;978978+ return DRM_ERR(EINVAL); 979979+ }980980+ } 981981+ if (state == state_error) {982982+ *hc_state = saved_state;983983+ return DRM_ERR(EINVAL);984984+ }985985+ return 0;986986+}987987+988988+int 989989+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size)990990+{991991+992992+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;993993+ uint32_t cmd;994994+ const uint32_t *buf_end = buf + ( size >> 2 );995995+ verifier_state_t state = state_command;996996+ int fire_count = 0;997997+998998+ while (buf < buf_end) {999999+10001000+ switch (state) {10011001+ case state_header2:10021002+ state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count );10031003+ break;10041004+ case state_header1:10051005+ state = via_parse_header1( dev_priv, &buf, buf_end );10061006+ break;10071007+ case state_vheader5:10081008+ state = via_parse_vheader5( dev_priv, &buf, buf_end );10091009+ break;10101010+ case state_vheader6:10111011+ state = via_parse_vheader6( dev_priv, &buf, buf_end );10121012+ break;10131013+ case state_command:10141014+ if (HALCYON_HEADER2 == (cmd = *buf)) 10151015+ state = state_header2;10161016+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 10171017+ state = state_header1;10181018+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)10191019+ state = state_vheader5;10201020+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)10211021+ state = state_vheader6;10221022+ else {10231023+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",10241024+ cmd);10251025+ state = state_error;10261026+ }10271027+ break;10281028+ case state_error:10291029+ default:10301030+ return DRM_ERR(EINVAL); 10311031+ }10321032+ } 10331033+ if (state == state_error) {10341034+ return DRM_ERR(EINVAL);10351035+ }10361036+ return 0;10371037+}10381038+10391039+10401040+10411041+static void 10421042+setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)10431043+{10441044+ int i;10451045+10461046+ for(i=0; i<256; ++i) {10471047+ table[i] = forbidden_command;10481048+ }10491049+10501050+ for(i=0; i<size; ++i) {10511051+ table[init_table[i].code] = init_table[i].hz;10521052+ }10531053+}10541054+10551055+void 10561056+via_init_command_verifier( void )10571057+{10581058+ setup_hazard_table(init_table1, table1, sizeof(init_table1) / sizeof(hz_init_t));10591059+ setup_hazard_table(init_table2, table2, sizeof(init_table2) / sizeof(hz_init_t));10601060+ setup_hazard_table(init_table3, table3, sizeof(init_table3) / sizeof(hz_init_t));10611061+}
+61
drivers/char/drm/via_verifier.h
···11+/*22+ * Copyright 2004 The Unichrome Project. All Rights Reserved.33+ *44+ * Permission is hereby granted, free of charge, to any person obtaining a55+ * copy of this software and associated documentation files (the "Software"),66+ * to deal in the Software without restriction, including without limitation77+ * the rights to use, copy, modify, merge, publish, distribute, sub license,88+ * and/or sell copies of the Software, and to permit persons to whom the99+ * Software is furnished to do so, subject to the following conditions:1010+ *1111+ * The above copyright notice and this permission notice (including the1212+ * next paragraph) shall be included in all copies or substantial portions1313+ * of the Software.1414+ *1515+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1616+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1717+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1818+ * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR1919+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2020+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2121+ * DEALINGS IN THE SOFTWARE.2222+ *2323+ * Author: Thomas Hellstr�m 2004.2424+ */2525+2626+#ifndef _VIA_VERIFIER_H_2727+#define _VIA_VERIFIER_H_2828+2929+typedef enum{3030+ no_sequence = 0, 3131+ z_address,3232+ dest_address,3333+ tex_address3434+}drm_via_sequence_t;3535+3636+3737+3838+typedef struct{3939+ unsigned texture;4040+ uint32_t z_addr; 4141+ uint32_t d_addr; 4242+ uint32_t t_addr[2][10];4343+ uint32_t pitch[2][10];4444+ uint32_t height[2][10];4545+ uint32_t tex_level_lo[2]; 4646+ uint32_t tex_level_hi[2];4747+ uint32_t tex_palette_size[2];4848+ drm_via_sequence_t unfinished;4949+ int agp_texture;5050+ int multitex;5151+ drm_device_t *dev;5252+ drm_map_t *map_cache;5353+ uint32_t vertex_count;5454+ int agp;5555+ const uint32_t *buf_start;5656+} drm_via_state_t;5757+5858+extern int via_verify_command_stream(const uint32_t * buf, unsigned int size, 5959+ drm_device_t *dev, int agp);6060+6161+#endif
+97
drivers/char/drm/via_video.c
···11+/*22+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.33+ *44+ * Permission is hereby granted, free of charge, to any person obtaining a55+ * copy of this software and associated documentation files (the "Software"),66+ * to deal in the Software without restriction, including without limitation77+ * the rights to use, copy, modify, merge, publish, distribute, sub license,88+ * and/or sell copies of the Software, and to permit persons to whom the99+ * Software is furnished to do so, subject to the following conditions:1010+ *1111+ * The above copyright notice and this permission notice (including the1212+ * next paragraph) shall be included in all copies or substantial portions1313+ * of the Software.1414+ *1515+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1616+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1717+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL1818+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR1919+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2020+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER2121+ * DEALINGS IN THE SOFTWARE.2222+ *2323+ * Author: Thomas Hellstrom 2005.2424+ *2525+ * Video and XvMC related functions.2626+ */2727+2828+#include "drmP.h"2929+#include "via_drm.h"3030+#include "via_drv.h"3131+3232+void3333+via_init_futex(drm_via_private_t *dev_priv)3434+{3535+ unsigned int i;3636+3737+ DRM_DEBUG("%s\n", __FUNCTION__);3838+3939+ for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {4040+ DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));4141+ XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;4242+ }4343+}4444+4545+void4646+via_cleanup_futex(drm_via_private_t *dev_priv)4747+{4848+} 4949+5050+void5151+via_release_futex(drm_via_private_t *dev_priv, int context)5252+{5353+ unsigned int i;5454+ volatile int *lock;5555+5656+ for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) {5757+ lock = (int *) XVMCLOCKPTR(dev_priv->sarea_priv, i);5858+ if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) {5959+ if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) {6060+ DRM_WAKEUP( &(dev_priv->decoder_queue[i]));6161+ }6262+ *lock = 0;6363+ }6464+ } 6565+} 6666+6767+int 6868+via_decoder_futex(DRM_IOCTL_ARGS)6969+{7070+ DRM_DEVICE;7171+ drm_via_futex_t fx;7272+ volatile int *lock;7373+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;7474+ drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;7575+ int ret = 0;7676+7777+ DRM_DEBUG("%s\n", __FUNCTION__);7878+7979+ DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx));8080+8181+ if (fx.lock > VIA_NR_XVMC_LOCKS)8282+ return -EFAULT;8383+8484+ lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock);8585+8686+ switch (fx.func) {8787+ case VIA_FUTEX_WAIT:8888+ DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],8989+ (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);9090+ return ret;9191+ case VIA_FUTEX_WAKE:9292+ DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));9393+ return 0;9494+ }9595+ return 0;9696+}9797+