Back to home page

OSCL-LXR

 
 

    


0001 /* savage_state.c -- State and drawing support for Savage
0002  *
0003  * Copyright 2004  Felix Kuehling
0004  * All Rights Reserved.
0005  *
0006  * Permission is hereby granted, free of charge, to any person obtaining a
0007  * copy of this software and associated documentation files (the "Software"),
0008  * to deal in the Software without restriction, including without limitation
0009  * the rights to use, copy, modify, merge, publish, distribute, sub license,
0010  * and/or sell copies of the Software, and to permit persons to whom the
0011  * Software is furnished to do so, subject to the following conditions:
0012  *
0013  * The above copyright notice and this permission notice (including the
0014  * next paragraph) shall be included in all copies or substantial portions
0015  * of the Software.
0016  *
0017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0018  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0020  * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
0021  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
0022  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0023  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0024  */
0025 
0026 #include <linux/slab.h>
0027 #include <linux/uaccess.h>
0028 
0029 #include <drm/drm_device.h>
0030 #include <drm/drm_file.h>
0031 #include <drm/drm_print.h>
0032 #include <drm/savage_drm.h>
0033 
0034 #include "savage_drv.h"
0035 
0036 void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
0037                    const struct drm_clip_rect * pbox)
0038 {
0039     uint32_t scstart = dev_priv->state.s3d.new_scstart;
0040     uint32_t scend = dev_priv->state.s3d.new_scend;
0041     scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
0042         ((uint32_t) pbox->x1 & 0x000007ff) |
0043         (((uint32_t) pbox->y1 << 16) & 0x07ff0000);
0044     scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) |
0045         (((uint32_t) pbox->x2 - 1) & 0x000007ff) |
0046         ((((uint32_t) pbox->y2 - 1) << 16) & 0x07ff0000);
0047     if (scstart != dev_priv->state.s3d.scstart ||
0048         scend != dev_priv->state.s3d.scend) {
0049         DMA_LOCALS;
0050         BEGIN_DMA(4);
0051         DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
0052         DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
0053         DMA_WRITE(scstart);
0054         DMA_WRITE(scend);
0055         dev_priv->state.s3d.scstart = scstart;
0056         dev_priv->state.s3d.scend = scend;
0057         dev_priv->waiting = 1;
0058         DMA_COMMIT();
0059     }
0060 }
0061 
0062 void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,
0063                   const struct drm_clip_rect * pbox)
0064 {
0065     uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
0066     uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
0067     drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
0068         ((uint32_t) pbox->x1 & 0x000007ff) |
0069         (((uint32_t) pbox->y1 << 12) & 0x00fff000);
0070     drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
0071         (((uint32_t) pbox->x2 - 1) & 0x000007ff) |
0072         ((((uint32_t) pbox->y2 - 1) << 12) & 0x00fff000);
0073     if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
0074         drawctrl1 != dev_priv->state.s4.drawctrl1) {
0075         DMA_LOCALS;
0076         BEGIN_DMA(4);
0077         DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
0078         DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
0079         DMA_WRITE(drawctrl0);
0080         DMA_WRITE(drawctrl1);
0081         dev_priv->state.s4.drawctrl0 = drawctrl0;
0082         dev_priv->state.s4.drawctrl1 = drawctrl1;
0083         dev_priv->waiting = 1;
0084         DMA_COMMIT();
0085     }
0086 }
0087 
0088 static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
0089                  uint32_t addr)
0090 {
0091     if ((addr & 6) != 2) {  /* reserved bits */
0092         DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
0093         return -EINVAL;
0094     }
0095     if (!(addr & 1)) {  /* local */
0096         addr &= ~7;
0097         if (addr < dev_priv->texture_offset ||
0098             addr >= dev_priv->texture_offset + dev_priv->texture_size) {
0099             DRM_ERROR
0100                 ("bad texAddr%d %08x (local addr out of range)\n",
0101                  unit, addr);
0102             return -EINVAL;
0103         }
0104     } else {        /* AGP */
0105         if (!dev_priv->agp_textures) {
0106             DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
0107                   unit, addr);
0108             return -EINVAL;
0109         }
0110         addr &= ~7;
0111         if (addr < dev_priv->agp_textures->offset ||
0112             addr >= (dev_priv->agp_textures->offset +
0113                  dev_priv->agp_textures->size)) {
0114             DRM_ERROR
0115                 ("bad texAddr%d %08x (AGP addr out of range)\n",
0116                  unit, addr);
0117             return -EINVAL;
0118         }
0119     }
0120     return 0;
0121 }
0122 
0123 #define SAVE_STATE(reg,where)           \
0124     if(start <= reg && start+count > reg)   \
0125         dev_priv->state.where = regs[reg - start]
0126 #define SAVE_STATE_MASK(reg,where,mask) do {            \
0127     if(start <= reg && start+count > reg) {         \
0128         uint32_t tmp;                   \
0129         tmp = regs[reg - start];            \
0130         dev_priv->state.where = (tmp & (mask)) |    \
0131             (dev_priv->state.where & ~(mask));  \
0132     }                           \
0133 } while (0)
0134 
0135 static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,
0136                    unsigned int start, unsigned int count,
0137                    const uint32_t *regs)
0138 {
0139     if (start < SAVAGE_TEXPALADDR_S3D ||
0140         start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
0141         DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
0142               start, start + count - 1);
0143         return -EINVAL;
0144     }
0145 
0146     SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
0147             ~SAVAGE_SCISSOR_MASK_S3D);
0148     SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
0149             ~SAVAGE_SCISSOR_MASK_S3D);
0150 
0151     /* if any texture regs were changed ... */
0152     if (start <= SAVAGE_TEXCTRL_S3D &&
0153         start + count > SAVAGE_TEXPALADDR_S3D) {
0154         /* ... check texture state */
0155         SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
0156         SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
0157         if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
0158             return savage_verify_texaddr(dev_priv, 0,
0159                         dev_priv->state.s3d.texaddr);
0160     }
0161 
0162     return 0;
0163 }
0164 
0165 static int savage_verify_state_s4(drm_savage_private_t * dev_priv,
0166                   unsigned int start, unsigned int count,
0167                   const uint32_t *regs)
0168 {
0169     int ret = 0;
0170 
0171     if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
0172         start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {
0173         DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
0174               start, start + count - 1);
0175         return -EINVAL;
0176     }
0177 
0178     SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
0179             ~SAVAGE_SCISSOR_MASK_S4);
0180     SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
0181             ~SAVAGE_SCISSOR_MASK_S4);
0182 
0183     /* if any texture regs were changed ... */
0184     if (start <= SAVAGE_TEXDESCR_S4 &&
0185         start + count > SAVAGE_TEXPALADDR_S4) {
0186         /* ... check texture state */
0187         SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
0188         SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
0189         SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
0190         if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
0191             ret |= savage_verify_texaddr(dev_priv, 0,
0192                         dev_priv->state.s4.texaddr0);
0193         if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
0194             ret |= savage_verify_texaddr(dev_priv, 1,
0195                         dev_priv->state.s4.texaddr1);
0196     }
0197 
0198     return ret;
0199 }
0200 
0201 #undef SAVE_STATE
0202 #undef SAVE_STATE_MASK
0203 
0204 static int savage_dispatch_state(drm_savage_private_t * dev_priv,
0205                  const drm_savage_cmd_header_t * cmd_header,
0206                  const uint32_t *regs)
0207 {
0208     unsigned int count = cmd_header->state.count;
0209     unsigned int start = cmd_header->state.start;
0210     unsigned int count2 = 0;
0211     unsigned int bci_size;
0212     int ret;
0213     DMA_LOCALS;
0214 
0215     if (!count)
0216         return 0;
0217 
0218     if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0219         ret = savage_verify_state_s3d(dev_priv, start, count, regs);
0220         if (ret != 0)
0221             return ret;
0222         /* scissor regs are emitted in savage_dispatch_draw */
0223         if (start < SAVAGE_SCSTART_S3D) {
0224             if (start + count > SAVAGE_SCEND_S3D + 1)
0225                 count2 = count - (SAVAGE_SCEND_S3D + 1 - start);
0226             if (start + count > SAVAGE_SCSTART_S3D)
0227                 count = SAVAGE_SCSTART_S3D - start;
0228         } else if (start <= SAVAGE_SCEND_S3D) {
0229             if (start + count > SAVAGE_SCEND_S3D + 1) {
0230                 count -= SAVAGE_SCEND_S3D + 1 - start;
0231                 start = SAVAGE_SCEND_S3D + 1;
0232             } else
0233                 return 0;
0234         }
0235     } else {
0236         ret = savage_verify_state_s4(dev_priv, start, count, regs);
0237         if (ret != 0)
0238             return ret;
0239         /* scissor regs are emitted in savage_dispatch_draw */
0240         if (start < SAVAGE_DRAWCTRL0_S4) {
0241             if (start + count > SAVAGE_DRAWCTRL1_S4 + 1)
0242                 count2 = count -
0243                      (SAVAGE_DRAWCTRL1_S4 + 1 - start);
0244             if (start + count > SAVAGE_DRAWCTRL0_S4)
0245                 count = SAVAGE_DRAWCTRL0_S4 - start;
0246         } else if (start <= SAVAGE_DRAWCTRL1_S4) {
0247             if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) {
0248                 count -= SAVAGE_DRAWCTRL1_S4 + 1 - start;
0249                 start = SAVAGE_DRAWCTRL1_S4 + 1;
0250             } else
0251                 return 0;
0252         }
0253     }
0254 
0255     bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255;
0256 
0257     if (cmd_header->state.global) {
0258         BEGIN_DMA(bci_size + 1);
0259         DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
0260         dev_priv->waiting = 1;
0261     } else {
0262         BEGIN_DMA(bci_size);
0263     }
0264 
0265     do {
0266         while (count > 0) {
0267             unsigned int n = count < 255 ? count : 255;
0268             DMA_SET_REGISTERS(start, n);
0269             DMA_COPY(regs, n);
0270             count -= n;
0271             start += n;
0272             regs += n;
0273         }
0274         start += 2;
0275         regs += 2;
0276         count = count2;
0277         count2 = 0;
0278     } while (count);
0279 
0280     DMA_COMMIT();
0281 
0282     return 0;
0283 }
0284 
0285 static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
0286                     const drm_savage_cmd_header_t * cmd_header,
0287                     const struct drm_buf * dmabuf)
0288 {
0289     unsigned char reorder = 0;
0290     unsigned int prim = cmd_header->prim.prim;
0291     unsigned int skip = cmd_header->prim.skip;
0292     unsigned int n = cmd_header->prim.count;
0293     unsigned int start = cmd_header->prim.start;
0294     unsigned int i;
0295     BCI_LOCALS;
0296 
0297     if (!dmabuf) {
0298         DRM_ERROR("called without dma buffers!\n");
0299         return -EINVAL;
0300     }
0301 
0302     if (!n)
0303         return 0;
0304 
0305     switch (prim) {
0306     case SAVAGE_PRIM_TRILIST_201:
0307         reorder = 1;
0308         prim = SAVAGE_PRIM_TRILIST;
0309         fallthrough;
0310     case SAVAGE_PRIM_TRILIST:
0311         if (n % 3 != 0) {
0312             DRM_ERROR("wrong number of vertices %u in TRILIST\n",
0313                   n);
0314             return -EINVAL;
0315         }
0316         break;
0317     case SAVAGE_PRIM_TRISTRIP:
0318     case SAVAGE_PRIM_TRIFAN:
0319         if (n < 3) {
0320             DRM_ERROR
0321                 ("wrong number of vertices %u in TRIFAN/STRIP\n",
0322                  n);
0323             return -EINVAL;
0324         }
0325         break;
0326     default:
0327         DRM_ERROR("invalid primitive type %u\n", prim);
0328         return -EINVAL;
0329     }
0330 
0331     if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0332         if (skip != 0) {
0333             DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
0334             return -EINVAL;
0335         }
0336     } else {
0337         unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
0338             (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
0339             (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
0340         if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
0341             DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
0342             return -EINVAL;
0343         }
0344         if (reorder) {
0345             DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
0346             return -EINVAL;
0347         }
0348     }
0349 
0350     if (start + n > dmabuf->total / 32) {
0351         DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
0352               start, start + n - 1, dmabuf->total / 32);
0353         return -EINVAL;
0354     }
0355 
0356     /* Vertex DMA doesn't work with command DMA at the same time,
0357      * so we use BCI_... to submit commands here. Flush buffered
0358      * faked DMA first. */
0359     DMA_FLUSH();
0360 
0361     if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
0362         BEGIN_BCI(2);
0363         BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
0364         BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
0365         dev_priv->state.common.vbaddr = dmabuf->bus_address;
0366     }
0367     if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
0368         /* Workaround for what looks like a hardware bug. If a
0369          * WAIT_3D_IDLE was emitted some time before the
0370          * indexed drawing command then the engine will lock
0371          * up. There are two known workarounds:
0372          * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
0373         BEGIN_BCI(63);
0374         for (i = 0; i < 63; ++i)
0375             BCI_WRITE(BCI_CMD_WAIT);
0376         dev_priv->waiting = 0;
0377     }
0378 
0379     prim <<= 25;
0380     while (n != 0) {
0381         /* Can emit up to 255 indices (85 triangles) at once. */
0382         unsigned int count = n > 255 ? 255 : n;
0383         if (reorder) {
0384             /* Need to reorder indices for correct flat
0385              * shading while preserving the clock sense
0386              * for correct culling. Only on Savage3D. */
0387             int reorder[3] = { -1, -1, -1 };
0388             reorder[start % 3] = 2;
0389 
0390             BEGIN_BCI((count + 1 + 1) / 2);
0391             BCI_DRAW_INDICES_S3D(count, prim, start + 2);
0392 
0393             for (i = start + 1; i + 1 < start + count; i += 2)
0394                 BCI_WRITE((i + reorder[i % 3]) |
0395                       ((i + 1 +
0396                         reorder[(i + 1) % 3]) << 16));
0397             if (i < start + count)
0398                 BCI_WRITE(i + reorder[i % 3]);
0399         } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0400             BEGIN_BCI((count + 1 + 1) / 2);
0401             BCI_DRAW_INDICES_S3D(count, prim, start);
0402 
0403             for (i = start + 1; i + 1 < start + count; i += 2)
0404                 BCI_WRITE(i | ((i + 1) << 16));
0405             if (i < start + count)
0406                 BCI_WRITE(i);
0407         } else {
0408             BEGIN_BCI((count + 2 + 1) / 2);
0409             BCI_DRAW_INDICES_S4(count, prim, skip);
0410 
0411             for (i = start; i + 1 < start + count; i += 2)
0412                 BCI_WRITE(i | ((i + 1) << 16));
0413             if (i < start + count)
0414                 BCI_WRITE(i);
0415         }
0416 
0417         start += count;
0418         n -= count;
0419 
0420         prim |= BCI_CMD_DRAW_CONT;
0421     }
0422 
0423     return 0;
0424 }
0425 
0426 static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
0427                    const drm_savage_cmd_header_t * cmd_header,
0428                    const uint32_t *vtxbuf, unsigned int vb_size,
0429                    unsigned int vb_stride)
0430 {
0431     unsigned char reorder = 0;
0432     unsigned int prim = cmd_header->prim.prim;
0433     unsigned int skip = cmd_header->prim.skip;
0434     unsigned int n = cmd_header->prim.count;
0435     unsigned int start = cmd_header->prim.start;
0436     unsigned int vtx_size;
0437     unsigned int i;
0438     DMA_LOCALS;
0439 
0440     if (!n)
0441         return 0;
0442 
0443     switch (prim) {
0444     case SAVAGE_PRIM_TRILIST_201:
0445         reorder = 1;
0446         prim = SAVAGE_PRIM_TRILIST;
0447         fallthrough;
0448     case SAVAGE_PRIM_TRILIST:
0449         if (n % 3 != 0) {
0450             DRM_ERROR("wrong number of vertices %u in TRILIST\n",
0451                   n);
0452             return -EINVAL;
0453         }
0454         break;
0455     case SAVAGE_PRIM_TRISTRIP:
0456     case SAVAGE_PRIM_TRIFAN:
0457         if (n < 3) {
0458             DRM_ERROR
0459                 ("wrong number of vertices %u in TRIFAN/STRIP\n",
0460                  n);
0461             return -EINVAL;
0462         }
0463         break;
0464     default:
0465         DRM_ERROR("invalid primitive type %u\n", prim);
0466         return -EINVAL;
0467     }
0468 
0469     if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0470         if (skip > SAVAGE_SKIP_ALL_S3D) {
0471             DRM_ERROR("invalid skip flags 0x%04x\n", skip);
0472             return -EINVAL;
0473         }
0474         vtx_size = 8;   /* full vertex */
0475     } else {
0476         if (skip > SAVAGE_SKIP_ALL_S4) {
0477             DRM_ERROR("invalid skip flags 0x%04x\n", skip);
0478             return -EINVAL;
0479         }
0480         vtx_size = 10;  /* full vertex */
0481     }
0482 
0483     vtx_size -= (skip & 1) + (skip >> 1 & 1) +
0484         (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
0485         (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
0486 
0487     if (vtx_size > vb_stride) {
0488         DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
0489               vtx_size, vb_stride);
0490         return -EINVAL;
0491     }
0492 
0493     if (start + n > vb_size / (vb_stride * 4)) {
0494         DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
0495               start, start + n - 1, vb_size / (vb_stride * 4));
0496         return -EINVAL;
0497     }
0498 
0499     prim <<= 25;
0500     while (n != 0) {
0501         /* Can emit up to 255 vertices (85 triangles) at once. */
0502         unsigned int count = n > 255 ? 255 : n;
0503         if (reorder) {
0504             /* Need to reorder vertices for correct flat
0505              * shading while preserving the clock sense
0506              * for correct culling. Only on Savage3D. */
0507             int reorder[3] = { -1, -1, -1 };
0508             reorder[start % 3] = 2;
0509 
0510             BEGIN_DMA(count * vtx_size + 1);
0511             DMA_DRAW_PRIMITIVE(count, prim, skip);
0512 
0513             for (i = start; i < start + count; ++i) {
0514                 unsigned int j = i + reorder[i % 3];
0515                 DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
0516             }
0517 
0518             DMA_COMMIT();
0519         } else {
0520             BEGIN_DMA(count * vtx_size + 1);
0521             DMA_DRAW_PRIMITIVE(count, prim, skip);
0522 
0523             if (vb_stride == vtx_size) {
0524                 DMA_COPY(&vtxbuf[vb_stride * start],
0525                      vtx_size * count);
0526             } else {
0527                 for (i = start; i < start + count; ++i) {
0528                     DMA_COPY(&vtxbuf [vb_stride * i],
0529                          vtx_size);
0530                 }
0531             }
0532 
0533             DMA_COMMIT();
0534         }
0535 
0536         start += count;
0537         n -= count;
0538 
0539         prim |= BCI_CMD_DRAW_CONT;
0540     }
0541 
0542     return 0;
0543 }
0544 
0545 static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
0546                    const drm_savage_cmd_header_t * cmd_header,
0547                    const uint16_t *idx,
0548                    const struct drm_buf * dmabuf)
0549 {
0550     unsigned char reorder = 0;
0551     unsigned int prim = cmd_header->idx.prim;
0552     unsigned int skip = cmd_header->idx.skip;
0553     unsigned int n = cmd_header->idx.count;
0554     unsigned int i;
0555     BCI_LOCALS;
0556 
0557     if (!dmabuf) {
0558         DRM_ERROR("called without dma buffers!\n");
0559         return -EINVAL;
0560     }
0561 
0562     if (!n)
0563         return 0;
0564 
0565     switch (prim) {
0566     case SAVAGE_PRIM_TRILIST_201:
0567         reorder = 1;
0568         prim = SAVAGE_PRIM_TRILIST;
0569         fallthrough;
0570     case SAVAGE_PRIM_TRILIST:
0571         if (n % 3 != 0) {
0572             DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
0573             return -EINVAL;
0574         }
0575         break;
0576     case SAVAGE_PRIM_TRISTRIP:
0577     case SAVAGE_PRIM_TRIFAN:
0578         if (n < 3) {
0579             DRM_ERROR
0580                 ("wrong number of indices %u in TRIFAN/STRIP\n", n);
0581             return -EINVAL;
0582         }
0583         break;
0584     default:
0585         DRM_ERROR("invalid primitive type %u\n", prim);
0586         return -EINVAL;
0587     }
0588 
0589     if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0590         if (skip != 0) {
0591             DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
0592             return -EINVAL;
0593         }
0594     } else {
0595         unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
0596             (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
0597             (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
0598         if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
0599             DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
0600             return -EINVAL;
0601         }
0602         if (reorder) {
0603             DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
0604             return -EINVAL;
0605         }
0606     }
0607 
0608     /* Vertex DMA doesn't work with command DMA at the same time,
0609      * so we use BCI_... to submit commands here. Flush buffered
0610      * faked DMA first. */
0611     DMA_FLUSH();
0612 
0613     if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
0614         BEGIN_BCI(2);
0615         BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
0616         BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
0617         dev_priv->state.common.vbaddr = dmabuf->bus_address;
0618     }
0619     if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
0620         /* Workaround for what looks like a hardware bug. If a
0621          * WAIT_3D_IDLE was emitted some time before the
0622          * indexed drawing command then the engine will lock
0623          * up. There are two known workarounds:
0624          * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
0625         BEGIN_BCI(63);
0626         for (i = 0; i < 63; ++i)
0627             BCI_WRITE(BCI_CMD_WAIT);
0628         dev_priv->waiting = 0;
0629     }
0630 
0631     prim <<= 25;
0632     while (n != 0) {
0633         /* Can emit up to 255 indices (85 triangles) at once. */
0634         unsigned int count = n > 255 ? 255 : n;
0635 
0636         /* check indices */
0637         for (i = 0; i < count; ++i) {
0638             if (idx[i] > dmabuf->total / 32) {
0639                 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
0640                       i, idx[i], dmabuf->total / 32);
0641                 return -EINVAL;
0642             }
0643         }
0644 
0645         if (reorder) {
0646             /* Need to reorder indices for correct flat
0647              * shading while preserving the clock sense
0648              * for correct culling. Only on Savage3D. */
0649             int reorder[3] = { 2, -1, -1 };
0650 
0651             BEGIN_BCI((count + 1 + 1) / 2);
0652             BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
0653 
0654             for (i = 1; i + 1 < count; i += 2)
0655                 BCI_WRITE(idx[i + reorder[i % 3]] |
0656                       (idx[i + 1 +
0657                        reorder[(i + 1) % 3]] << 16));
0658             if (i < count)
0659                 BCI_WRITE(idx[i + reorder[i % 3]]);
0660         } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0661             BEGIN_BCI((count + 1 + 1) / 2);
0662             BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
0663 
0664             for (i = 1; i + 1 < count; i += 2)
0665                 BCI_WRITE(idx[i] | (idx[i + 1] << 16));
0666             if (i < count)
0667                 BCI_WRITE(idx[i]);
0668         } else {
0669             BEGIN_BCI((count + 2 + 1) / 2);
0670             BCI_DRAW_INDICES_S4(count, prim, skip);
0671 
0672             for (i = 0; i + 1 < count; i += 2)
0673                 BCI_WRITE(idx[i] | (idx[i + 1] << 16));
0674             if (i < count)
0675                 BCI_WRITE(idx[i]);
0676         }
0677 
0678         idx += count;
0679         n -= count;
0680 
0681         prim |= BCI_CMD_DRAW_CONT;
0682     }
0683 
0684     return 0;
0685 }
0686 
0687 static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
0688                   const drm_savage_cmd_header_t * cmd_header,
0689                   const uint16_t *idx,
0690                   const uint32_t *vtxbuf,
0691                   unsigned int vb_size, unsigned int vb_stride)
0692 {
0693     unsigned char reorder = 0;
0694     unsigned int prim = cmd_header->idx.prim;
0695     unsigned int skip = cmd_header->idx.skip;
0696     unsigned int n = cmd_header->idx.count;
0697     unsigned int vtx_size;
0698     unsigned int i;
0699     DMA_LOCALS;
0700 
0701     if (!n)
0702         return 0;
0703 
0704     switch (prim) {
0705     case SAVAGE_PRIM_TRILIST_201:
0706         reorder = 1;
0707         prim = SAVAGE_PRIM_TRILIST;
0708         fallthrough;
0709     case SAVAGE_PRIM_TRILIST:
0710         if (n % 3 != 0) {
0711             DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
0712             return -EINVAL;
0713         }
0714         break;
0715     case SAVAGE_PRIM_TRISTRIP:
0716     case SAVAGE_PRIM_TRIFAN:
0717         if (n < 3) {
0718             DRM_ERROR
0719                 ("wrong number of indices %u in TRIFAN/STRIP\n", n);
0720             return -EINVAL;
0721         }
0722         break;
0723     default:
0724         DRM_ERROR("invalid primitive type %u\n", prim);
0725         return -EINVAL;
0726     }
0727 
0728     if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
0729         if (skip > SAVAGE_SKIP_ALL_S3D) {
0730             DRM_ERROR("invalid skip flags 0x%04x\n", skip);
0731             return -EINVAL;
0732         }
0733         vtx_size = 8;   /* full vertex */
0734     } else {
0735         if (skip > SAVAGE_SKIP_ALL_S4) {
0736             DRM_ERROR("invalid skip flags 0x%04x\n", skip);
0737             return -EINVAL;
0738         }
0739         vtx_size = 10;  /* full vertex */
0740     }
0741 
0742     vtx_size -= (skip & 1) + (skip >> 1 & 1) +
0743         (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
0744         (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
0745 
0746     if (vtx_size > vb_stride) {
0747         DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
0748               vtx_size, vb_stride);
0749         return -EINVAL;
0750     }
0751 
0752     prim <<= 25;
0753     while (n != 0) {
0754         /* Can emit up to 255 vertices (85 triangles) at once. */
0755         unsigned int count = n > 255 ? 255 : n;
0756 
0757         /* Check indices */
0758         for (i = 0; i < count; ++i) {
0759             if (idx[i] > vb_size / (vb_stride * 4)) {
0760                 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
0761                       i, idx[i], vb_size / (vb_stride * 4));
0762                 return -EINVAL;
0763             }
0764         }
0765 
0766         if (reorder) {
0767             /* Need to reorder vertices for correct flat
0768              * shading while preserving the clock sense
0769              * for correct culling. Only on Savage3D. */
0770             int reorder[3] = { 2, -1, -1 };
0771 
0772             BEGIN_DMA(count * vtx_size + 1);
0773             DMA_DRAW_PRIMITIVE(count, prim, skip);
0774 
0775             for (i = 0; i < count; ++i) {
0776                 unsigned int j = idx[i + reorder[i % 3]];
0777                 DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
0778             }
0779 
0780             DMA_COMMIT();
0781         } else {
0782             BEGIN_DMA(count * vtx_size + 1);
0783             DMA_DRAW_PRIMITIVE(count, prim, skip);
0784 
0785             for (i = 0; i < count; ++i) {
0786                 unsigned int j = idx[i];
0787                 DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
0788             }
0789 
0790             DMA_COMMIT();
0791         }
0792 
0793         idx += count;
0794         n -= count;
0795 
0796         prim |= BCI_CMD_DRAW_CONT;
0797     }
0798 
0799     return 0;
0800 }
0801 
0802 static int savage_dispatch_clear(drm_savage_private_t * dev_priv,
0803                  const drm_savage_cmd_header_t * cmd_header,
0804                  const drm_savage_cmd_header_t *data,
0805                  unsigned int nbox,
0806                  const struct drm_clip_rect *boxes)
0807 {
0808     unsigned int flags = cmd_header->clear0.flags;
0809     unsigned int clear_cmd;
0810     unsigned int i, nbufs;
0811     DMA_LOCALS;
0812 
0813     if (nbox == 0)
0814         return 0;
0815 
0816     clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
0817         BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
0818     BCI_CMD_SET_ROP(clear_cmd, 0xCC);
0819 
0820     nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
0821         ((flags & SAVAGE_BACK) ? 1 : 0) + ((flags & SAVAGE_DEPTH) ? 1 : 0);
0822     if (nbufs == 0)
0823         return 0;
0824 
0825     if (data->clear1.mask != 0xffffffff) {
0826         /* set mask */
0827         BEGIN_DMA(2);
0828         DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
0829         DMA_WRITE(data->clear1.mask);
0830         DMA_COMMIT();
0831     }
0832     for (i = 0; i < nbox; ++i) {
0833         unsigned int x, y, w, h;
0834         unsigned int buf;
0835         x = boxes[i].x1, y = boxes[i].y1;
0836         w = boxes[i].x2 - boxes[i].x1;
0837         h = boxes[i].y2 - boxes[i].y1;
0838         BEGIN_DMA(nbufs * 6);
0839         for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
0840             if (!(flags & buf))
0841                 continue;
0842             DMA_WRITE(clear_cmd);
0843             switch (buf) {
0844             case SAVAGE_FRONT:
0845                 DMA_WRITE(dev_priv->front_offset);
0846                 DMA_WRITE(dev_priv->front_bd);
0847                 break;
0848             case SAVAGE_BACK:
0849                 DMA_WRITE(dev_priv->back_offset);
0850                 DMA_WRITE(dev_priv->back_bd);
0851                 break;
0852             case SAVAGE_DEPTH:
0853                 DMA_WRITE(dev_priv->depth_offset);
0854                 DMA_WRITE(dev_priv->depth_bd);
0855                 break;
0856             }
0857             DMA_WRITE(data->clear1.value);
0858             DMA_WRITE(BCI_X_Y(x, y));
0859             DMA_WRITE(BCI_W_H(w, h));
0860         }
0861         DMA_COMMIT();
0862     }
0863     if (data->clear1.mask != 0xffffffff) {
0864         /* reset mask */
0865         BEGIN_DMA(2);
0866         DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
0867         DMA_WRITE(0xffffffff);
0868         DMA_COMMIT();
0869     }
0870 
0871     return 0;
0872 }
0873 
0874 static int savage_dispatch_swap(drm_savage_private_t * dev_priv,
0875                 unsigned int nbox, const struct drm_clip_rect *boxes)
0876 {
0877     unsigned int swap_cmd;
0878     unsigned int i;
0879     DMA_LOCALS;
0880 
0881     if (nbox == 0)
0882         return 0;
0883 
0884     swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
0885         BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
0886     BCI_CMD_SET_ROP(swap_cmd, 0xCC);
0887 
0888     for (i = 0; i < nbox; ++i) {
0889         BEGIN_DMA(6);
0890         DMA_WRITE(swap_cmd);
0891         DMA_WRITE(dev_priv->back_offset);
0892         DMA_WRITE(dev_priv->back_bd);
0893         DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
0894         DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
0895         DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1,
0896                   boxes[i].y2 - boxes[i].y1));
0897         DMA_COMMIT();
0898     }
0899 
0900     return 0;
0901 }
0902 
0903 static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
0904                 const drm_savage_cmd_header_t *start,
0905                 const drm_savage_cmd_header_t *end,
0906                 const struct drm_buf * dmabuf,
0907                 const unsigned int *vtxbuf,
0908                 unsigned int vb_size, unsigned int vb_stride,
0909                 unsigned int nbox,
0910                 const struct drm_clip_rect *boxes)
0911 {
0912     unsigned int i, j;
0913     int ret;
0914 
0915     for (i = 0; i < nbox; ++i) {
0916         const drm_savage_cmd_header_t *cmdbuf;
0917         dev_priv->emit_clip_rect(dev_priv, &boxes[i]);
0918 
0919         cmdbuf = start;
0920         while (cmdbuf < end) {
0921             drm_savage_cmd_header_t cmd_header;
0922             cmd_header = *cmdbuf;
0923             cmdbuf++;
0924             switch (cmd_header.cmd.cmd) {
0925             case SAVAGE_CMD_DMA_PRIM:
0926                 ret = savage_dispatch_dma_prim(
0927                     dev_priv, &cmd_header, dmabuf);
0928                 break;
0929             case SAVAGE_CMD_VB_PRIM:
0930                 ret = savage_dispatch_vb_prim(
0931                     dev_priv, &cmd_header,
0932                     vtxbuf, vb_size, vb_stride);
0933                 break;
0934             case SAVAGE_CMD_DMA_IDX:
0935                 j = (cmd_header.idx.count + 3) / 4;
0936                 /* j was check in savage_bci_cmdbuf */
0937                 ret = savage_dispatch_dma_idx(dev_priv,
0938                     &cmd_header, (const uint16_t *)cmdbuf,
0939                     dmabuf);
0940                 cmdbuf += j;
0941                 break;
0942             case SAVAGE_CMD_VB_IDX:
0943                 j = (cmd_header.idx.count + 3) / 4;
0944                 /* j was check in savage_bci_cmdbuf */
0945                 ret = savage_dispatch_vb_idx(dev_priv,
0946                     &cmd_header, (const uint16_t *)cmdbuf,
0947                     (const uint32_t *)vtxbuf, vb_size,
0948                     vb_stride);
0949                 cmdbuf += j;
0950                 break;
0951             default:
0952                 /* What's the best return code? EFAULT? */
0953                 DRM_ERROR("IMPLEMENTATION ERROR: "
0954                       "non-drawing-command %d\n",
0955                       cmd_header.cmd.cmd);
0956                 return -EINVAL;
0957             }
0958 
0959             if (ret != 0)
0960                 return ret;
0961         }
0962     }
0963 
0964     return 0;
0965 }
0966 
0967 int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
0968 {
0969     drm_savage_private_t *dev_priv = dev->dev_private;
0970     struct drm_device_dma *dma = dev->dma;
0971     struct drm_buf *dmabuf;
0972     drm_savage_cmdbuf_t *cmdbuf = data;
0973     drm_savage_cmd_header_t *kcmd_addr = NULL;
0974     drm_savage_cmd_header_t *first_draw_cmd;
0975     unsigned int *kvb_addr = NULL;
0976     struct drm_clip_rect *kbox_addr = NULL;
0977     unsigned int i, j;
0978     int ret = 0;
0979 
0980     DRM_DEBUG("\n");
0981 
0982     LOCK_TEST_WITH_RETURN(dev, file_priv);
0983 
0984     if (dma && dma->buflist) {
0985         if (cmdbuf->dma_idx >= dma->buf_count) {
0986             DRM_ERROR
0987                 ("vertex buffer index %u out of range (0-%u)\n",
0988                  cmdbuf->dma_idx, dma->buf_count - 1);
0989             return -EINVAL;
0990         }
0991         dmabuf = dma->buflist[cmdbuf->dma_idx];
0992     } else {
0993         dmabuf = NULL;
0994     }
0995 
0996     /* Copy the user buffers into kernel temporary areas.  This hasn't been
0997      * a performance loss compared to VERIFYAREA_READ/
0998      * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
0999      * for locking on FreeBSD.
1000      */
1001     if (cmdbuf->size) {
1002         kcmd_addr = kmalloc_array(cmdbuf->size, 8, GFP_KERNEL);
1003         if (kcmd_addr == NULL)
1004             return -ENOMEM;
1005 
1006         if (copy_from_user(kcmd_addr, cmdbuf->cmd_addr,
1007                        cmdbuf->size * 8))
1008         {
1009             kfree(kcmd_addr);
1010             return -EFAULT;
1011         }
1012         cmdbuf->cmd_addr = kcmd_addr;
1013     }
1014     if (cmdbuf->vb_size) {
1015         kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size);
1016         if (IS_ERR(kvb_addr)) {
1017             ret = PTR_ERR(kvb_addr);
1018             kvb_addr = NULL;
1019             goto done;
1020         }
1021         cmdbuf->vb_addr = kvb_addr;
1022     }
1023     if (cmdbuf->nbox) {
1024         kbox_addr = kmalloc_array(cmdbuf->nbox, sizeof(struct drm_clip_rect),
1025                       GFP_KERNEL);
1026         if (kbox_addr == NULL) {
1027             ret = -ENOMEM;
1028             goto done;
1029         }
1030 
1031         if (copy_from_user(kbox_addr, cmdbuf->box_addr,
1032                        cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
1033             ret = -EFAULT;
1034             goto done;
1035         }
1036     cmdbuf->box_addr = kbox_addr;
1037     }
1038 
1039     /* Make sure writes to DMA buffers are finished before sending
1040      * DMA commands to the graphics hardware. */
1041     mb();
1042 
1043     /* Coming from user space. Don't know if the Xserver has
1044      * emitted wait commands. Assuming the worst. */
1045     dev_priv->waiting = 1;
1046 
1047     i = 0;
1048     first_draw_cmd = NULL;
1049     while (i < cmdbuf->size) {
1050         drm_savage_cmd_header_t cmd_header;
1051         cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr;
1052         cmdbuf->cmd_addr++;
1053         i++;
1054 
1055         /* Group drawing commands with same state to minimize
1056          * iterations over clip rects. */
1057         j = 0;
1058         switch (cmd_header.cmd.cmd) {
1059         case SAVAGE_CMD_DMA_IDX:
1060         case SAVAGE_CMD_VB_IDX:
1061             j = (cmd_header.idx.count + 3) / 4;
1062             if (i + j > cmdbuf->size) {
1063                 DRM_ERROR("indexed drawing command extends "
1064                       "beyond end of command buffer\n");
1065                 DMA_FLUSH();
1066                 ret = -EINVAL;
1067                 goto done;
1068             }
1069             fallthrough;
1070         case SAVAGE_CMD_DMA_PRIM:
1071         case SAVAGE_CMD_VB_PRIM:
1072             if (!first_draw_cmd)
1073                 first_draw_cmd = cmdbuf->cmd_addr - 1;
1074             cmdbuf->cmd_addr += j;
1075             i += j;
1076             break;
1077         default:
1078             if (first_draw_cmd) {
1079                 ret = savage_dispatch_draw(
1080                       dev_priv, first_draw_cmd,
1081                       cmdbuf->cmd_addr - 1,
1082                       dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size,
1083                       cmdbuf->vb_stride,
1084                       cmdbuf->nbox, cmdbuf->box_addr);
1085                 if (ret != 0)
1086                     goto done;
1087                 first_draw_cmd = NULL;
1088             }
1089         }
1090         if (first_draw_cmd)
1091             continue;
1092 
1093         switch (cmd_header.cmd.cmd) {
1094         case SAVAGE_CMD_STATE:
1095             j = (cmd_header.state.count + 1) / 2;
1096             if (i + j > cmdbuf->size) {
1097                 DRM_ERROR("command SAVAGE_CMD_STATE extends "
1098                       "beyond end of command buffer\n");
1099                 DMA_FLUSH();
1100                 ret = -EINVAL;
1101                 goto done;
1102             }
1103             ret = savage_dispatch_state(dev_priv, &cmd_header,
1104                 (const uint32_t *)cmdbuf->cmd_addr);
1105             cmdbuf->cmd_addr += j;
1106             i += j;
1107             break;
1108         case SAVAGE_CMD_CLEAR:
1109             if (i + 1 > cmdbuf->size) {
1110                 DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
1111                       "beyond end of command buffer\n");
1112                 DMA_FLUSH();
1113                 ret = -EINVAL;
1114                 goto done;
1115             }
1116             ret = savage_dispatch_clear(dev_priv, &cmd_header,
1117                             cmdbuf->cmd_addr,
1118                             cmdbuf->nbox,
1119                             cmdbuf->box_addr);
1120             cmdbuf->cmd_addr++;
1121             i++;
1122             break;
1123         case SAVAGE_CMD_SWAP:
1124             ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox,
1125                            cmdbuf->box_addr);
1126             break;
1127         default:
1128             DRM_ERROR("invalid command 0x%x\n",
1129                   cmd_header.cmd.cmd);
1130             DMA_FLUSH();
1131             ret = -EINVAL;
1132             goto done;
1133         }
1134 
1135         if (ret != 0) {
1136             DMA_FLUSH();
1137             goto done;
1138         }
1139     }
1140 
1141     if (first_draw_cmd) {
1142         ret = savage_dispatch_draw (
1143             dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf,
1144             cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride,
1145             cmdbuf->nbox, cmdbuf->box_addr);
1146         if (ret != 0) {
1147             DMA_FLUSH();
1148             goto done;
1149         }
1150     }
1151 
1152     DMA_FLUSH();
1153 
1154     if (dmabuf && cmdbuf->discard) {
1155         drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
1156         uint16_t event;
1157         event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
1158         SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
1159         savage_freelist_put(dev, dmabuf);
1160     }
1161 
1162 done:
1163     /* If we didn't need to allocate them, these'll be NULL */
1164     kfree(kcmd_addr);
1165     kfree(kvb_addr);
1166     kfree(kbox_addr);
1167 
1168     return ret;
1169 }