16393Scg149915
26393Scg149915 /*
36393Scg149915 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
46393Scg149915 * Use is subject to license terms.
56393Scg149915 */
66393Scg149915 /* radeon_state.c -- State support for Radeon -*- linux-c -*- */
76393Scg149915 /*
86393Scg149915 * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
96393Scg149915 * All Rights Reserved.
106393Scg149915 *
116393Scg149915 * Permission is hereby granted, free of charge, to any person obtaining a
126393Scg149915 * copy of this software and associated documentation files (the "Software"),
136393Scg149915 * to deal in the Software without restriction, including without limitation
146393Scg149915 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
156393Scg149915 * and/or sell copies of the Software, and to permit persons to whom the
166393Scg149915 * Software is furnished to do so, subject to the following conditions:
176393Scg149915 *
186393Scg149915 * The above copyright notice and this permission notice (including the next
196393Scg149915 * paragraph) shall be included in all copies or substantial portions of the
206393Scg149915 * Software.
216393Scg149915 *
226393Scg149915 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
236393Scg149915 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
246393Scg149915 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
256393Scg149915 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
266393Scg149915 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
276393Scg149915 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
286393Scg149915 * DEALINGS IN THE SOFTWARE.
296393Scg149915 *
306393Scg149915 * Authors:
316393Scg149915 * Gareth Hughes <gareth@valinux.com>
326393Scg149915 * Kevin E. Martin <martin@valinux.com>
336393Scg149915 */
346393Scg149915
356393Scg149915 #pragma ident "%Z%%M% %I% %E% SMI"
366393Scg149915
376393Scg149915 #include "drmP.h"
386393Scg149915 #include "drm.h"
396393Scg149915 #include "drm_sarea.h"
406393Scg149915 #include "radeon_drm.h"
416393Scg149915 #include "radeon_drv.h"
426393Scg149915 #include "radeon_io32.h"
436393Scg149915
446393Scg149915 /*
456393Scg149915 * Helper functions for client state checking and fixup
466393Scg149915 */
476393Scg149915
486393Scg149915 static inline int
radeon_check_and_fixup_offset(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,u32 * offset)496393Scg149915 radeon_check_and_fixup_offset(drm_radeon_private_t *dev_priv,
506393Scg149915 drm_file_t *filp_priv, u32 *offset)
516393Scg149915 {
526393Scg149915 u64 off = *offset;
536393Scg149915 u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
546393Scg149915 struct drm_radeon_driver_file_fields *radeon_priv;
556393Scg149915
566393Scg149915 /*
576393Scg149915 * Hrm ... the story of the offset ... So this function converts
586393Scg149915 * the various ideas of what userland clients might have for an
596393Scg149915 * offset in the card address space into an offset into the card
606393Scg149915 * address space :) So with a sane client, it should just keep
616393Scg149915 * the value intact and just do some boundary checking. However,
626393Scg149915 * not all clients are sane. Some older clients pass us 0 based
636393Scg149915 * offsets relative to the start of the framebuffer and some may
646393Scg149915 * assume the AGP aperture it appended to the framebuffer, so we
656393Scg149915 * try to detect those cases and fix them up.
666393Scg149915 *
676393Scg149915 * Note: It might be a good idea here to make sure the offset lands
686393Scg149915 * in some "allowed" area to protect things like the PCIE GART...
696393Scg149915 */
706393Scg149915
716393Scg149915 /*
726393Scg149915 * First, the best case, the offset already lands in either the
736393Scg149915 * framebuffer or the GART mapped space
746393Scg149915 */
756393Scg149915
76*7053Shh224818 if (RADEON_CHECK_OFFSET(dev_priv, off))
776393Scg149915 return (0);
786393Scg149915
796393Scg149915 /*
806393Scg149915 * Ok, that didn't happen... now check if we have a zero based
816393Scg149915 * offset that fits in the framebuffer + gart space, apply the
826393Scg149915 * magic offset we get from SETPARAM or calculated from fb_location
836393Scg149915 */
846393Scg149915 if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
856393Scg149915 radeon_priv = filp_priv->driver_priv;
866393Scg149915 off += radeon_priv->radeon_fb_delta;
876393Scg149915 }
886393Scg149915
896393Scg149915 /* Finally, assume we aimed at a GART offset if beyond the fb */
906393Scg149915 if (off > fb_end)
916393Scg149915 off = off - fb_end - 1 + dev_priv->gart_vm_start;
926393Scg149915
936393Scg149915 /* Now recheck and fail if out of bounds */
94*7053Shh224818 if (RADEON_CHECK_OFFSET(dev_priv, off)) {
956393Scg149915 DRM_DEBUG("offset fixed up to 0x%x\n", off);
966393Scg149915 *offset = (uint32_t)off;
976393Scg149915 return (0);
986393Scg149915 }
996393Scg149915 return (EINVAL);
1006393Scg149915 }
1016393Scg149915
1026393Scg149915 static inline int
radeon_check_and_fixup_packets(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,int id,u32 * data)1036393Scg149915 radeon_check_and_fixup_packets(drm_radeon_private_t *dev_priv,
1046393Scg149915 drm_file_t *filp_priv, int id, u32 *data)
1056393Scg149915 {
1066393Scg149915 switch (id) {
1076393Scg149915
1086393Scg149915 case RADEON_EMIT_PP_MISC:
1096393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
1106393Scg149915 &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
1116393Scg149915 DRM_ERROR("Invalid depth buffer offset\n");
1126393Scg149915 return (EINVAL);
1136393Scg149915 }
1146393Scg149915 break;
1156393Scg149915
1166393Scg149915 case RADEON_EMIT_PP_CNTL:
1176393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
1186393Scg149915 &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
1196393Scg149915 DRM_ERROR("Invalid colour buffer offset\n");
1206393Scg149915 return (EINVAL);
1216393Scg149915 }
1226393Scg149915 break;
1236393Scg149915
1246393Scg149915 case R200_EMIT_PP_TXOFFSET_0:
1256393Scg149915 case R200_EMIT_PP_TXOFFSET_1:
1266393Scg149915 case R200_EMIT_PP_TXOFFSET_2:
1276393Scg149915 case R200_EMIT_PP_TXOFFSET_3:
1286393Scg149915 case R200_EMIT_PP_TXOFFSET_4:
1296393Scg149915 case R200_EMIT_PP_TXOFFSET_5:
1306393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
1316393Scg149915 &data[0])) {
1326393Scg149915 DRM_ERROR("Invalid R200 texture offset\n");
1336393Scg149915 return (EINVAL);
1346393Scg149915 }
1356393Scg149915 break;
1366393Scg149915
1376393Scg149915 case RADEON_EMIT_PP_TXFILTER_0:
1386393Scg149915 case RADEON_EMIT_PP_TXFILTER_1:
1396393Scg149915 case RADEON_EMIT_PP_TXFILTER_2:
1406393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
1416393Scg149915 &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
1426393Scg149915 DRM_ERROR("Invalid R100 texture offset\n");
1436393Scg149915 return (EINVAL);
1446393Scg149915 }
1456393Scg149915 break;
1466393Scg149915
1476393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_0:
1486393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_1:
1496393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_2:
1506393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_3:
1516393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_4:
1526393Scg149915 case R200_EMIT_PP_CUBIC_OFFSETS_5: {
1536393Scg149915 int i;
1546393Scg149915 for (i = 0; i < 5; i++) {
1556393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
1566393Scg149915 filp_priv, &data[i])) {
1576393Scg149915 DRM_ERROR("Invalid R200 cubic"
1586393Scg149915 " texture offset\n");
1596393Scg149915 return (EINVAL);
1606393Scg149915 }
1616393Scg149915 }
1626393Scg149915 break;
1636393Scg149915 }
1646393Scg149915
1656393Scg149915 case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
1666393Scg149915 case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
1676393Scg149915 case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:
1686393Scg149915 {
1696393Scg149915 int i;
1706393Scg149915 for (i = 0; i < 5; i++) {
1716393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
1726393Scg149915 filp_priv, &data[i])) {
1736393Scg149915 DRM_ERROR("Invalid R100 cubic"
1746393Scg149915 " texture offset\n");
1756393Scg149915 return (EINVAL);
1766393Scg149915 }
1776393Scg149915 }
1786393Scg149915 }
1796393Scg149915 break;
1806393Scg149915
1816393Scg149915 case R200_EMIT_VAP_CTL:
1826393Scg149915 {
1836393Scg149915 RING_LOCALS;
1846393Scg149915 BEGIN_RING(2);
1856393Scg149915 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
1866393Scg149915 ADVANCE_RING();
1876393Scg149915 }
1886393Scg149915 break;
1896393Scg149915
1906393Scg149915 case RADEON_EMIT_RB3D_COLORPITCH:
1916393Scg149915 case RADEON_EMIT_RE_LINE_PATTERN:
1926393Scg149915 case RADEON_EMIT_SE_LINE_WIDTH:
1936393Scg149915 case RADEON_EMIT_PP_LUM_MATRIX:
1946393Scg149915 case RADEON_EMIT_PP_ROT_MATRIX_0:
1956393Scg149915 case RADEON_EMIT_RB3D_STENCILREFMASK:
1966393Scg149915 case RADEON_EMIT_SE_VPORT_XSCALE:
1976393Scg149915 case RADEON_EMIT_SE_CNTL:
1986393Scg149915 case RADEON_EMIT_SE_CNTL_STATUS:
1996393Scg149915 case RADEON_EMIT_RE_MISC:
2006393Scg149915 case RADEON_EMIT_PP_BORDER_COLOR_0:
2016393Scg149915 case RADEON_EMIT_PP_BORDER_COLOR_1:
2026393Scg149915 case RADEON_EMIT_PP_BORDER_COLOR_2:
2036393Scg149915 case RADEON_EMIT_SE_ZBIAS_FACTOR:
2046393Scg149915 case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
2056393Scg149915 case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
2066393Scg149915 case R200_EMIT_PP_TXCBLEND_0:
2076393Scg149915 case R200_EMIT_PP_TXCBLEND_1:
2086393Scg149915 case R200_EMIT_PP_TXCBLEND_2:
2096393Scg149915 case R200_EMIT_PP_TXCBLEND_3:
2106393Scg149915 case R200_EMIT_PP_TXCBLEND_4:
2116393Scg149915 case R200_EMIT_PP_TXCBLEND_5:
2126393Scg149915 case R200_EMIT_PP_TXCBLEND_6:
2136393Scg149915 case R200_EMIT_PP_TXCBLEND_7:
2146393Scg149915 case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
2156393Scg149915 case R200_EMIT_TFACTOR_0:
2166393Scg149915 case R200_EMIT_VTX_FMT_0:
2176393Scg149915 case R200_EMIT_MATRIX_SELECT_0:
2186393Scg149915 case R200_EMIT_TEX_PROC_CTL_2:
2196393Scg149915 case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
2206393Scg149915 case R200_EMIT_PP_TXFILTER_0:
2216393Scg149915 case R200_EMIT_PP_TXFILTER_1:
2226393Scg149915 case R200_EMIT_PP_TXFILTER_2:
2236393Scg149915 case R200_EMIT_PP_TXFILTER_3:
2246393Scg149915 case R200_EMIT_PP_TXFILTER_4:
2256393Scg149915 case R200_EMIT_PP_TXFILTER_5:
2266393Scg149915 case R200_EMIT_VTE_CNTL:
2276393Scg149915 case R200_EMIT_OUTPUT_VTX_COMP_SEL:
2286393Scg149915 case R200_EMIT_PP_TAM_DEBUG3:
2296393Scg149915 case R200_EMIT_PP_CNTL_X:
2306393Scg149915 case R200_EMIT_RB3D_DEPTHXY_OFFSET:
2316393Scg149915 case R200_EMIT_RE_AUX_SCISSOR_CNTL:
2326393Scg149915 case R200_EMIT_RE_SCISSOR_TL_0:
2336393Scg149915 case R200_EMIT_RE_SCISSOR_TL_1:
2346393Scg149915 case R200_EMIT_RE_SCISSOR_TL_2:
2356393Scg149915 case R200_EMIT_SE_VAP_CNTL_STATUS:
2366393Scg149915 case R200_EMIT_SE_VTX_STATE_CNTL:
2376393Scg149915 case R200_EMIT_RE_POINTSIZE:
2386393Scg149915 case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
2396393Scg149915 case R200_EMIT_PP_CUBIC_FACES_0:
2406393Scg149915 case R200_EMIT_PP_CUBIC_FACES_1:
2416393Scg149915 case R200_EMIT_PP_CUBIC_FACES_2:
2426393Scg149915 case R200_EMIT_PP_CUBIC_FACES_3:
2436393Scg149915 case R200_EMIT_PP_CUBIC_FACES_4:
2446393Scg149915 case R200_EMIT_PP_CUBIC_FACES_5:
2456393Scg149915 case RADEON_EMIT_PP_TEX_SIZE_0:
2466393Scg149915 case RADEON_EMIT_PP_TEX_SIZE_1:
2476393Scg149915 case RADEON_EMIT_PP_TEX_SIZE_2:
2486393Scg149915 case R200_EMIT_RB3D_BLENDCOLOR:
2496393Scg149915 case R200_EMIT_TCL_POINT_SPRITE_CNTL:
2506393Scg149915 case RADEON_EMIT_PP_CUBIC_FACES_0:
2516393Scg149915 case RADEON_EMIT_PP_CUBIC_FACES_1:
2526393Scg149915 case RADEON_EMIT_PP_CUBIC_FACES_2:
2536393Scg149915 case R200_EMIT_PP_TRI_PERF_CNTL:
2546393Scg149915 case R200_EMIT_PP_AFS_0:
2556393Scg149915 case R200_EMIT_PP_AFS_1:
2566393Scg149915 case R200_EMIT_ATF_TFACTOR:
2576393Scg149915 case R200_EMIT_PP_TXCTLALL_0:
2586393Scg149915 case R200_EMIT_PP_TXCTLALL_1:
2596393Scg149915 case R200_EMIT_PP_TXCTLALL_2:
2606393Scg149915 case R200_EMIT_PP_TXCTLALL_3:
2616393Scg149915 case R200_EMIT_PP_TXCTLALL_4:
2626393Scg149915 case R200_EMIT_PP_TXCTLALL_5:
2636393Scg149915 case R200_EMIT_VAP_PVS_CNTL:
2646393Scg149915 /* These packets don't contain memory offsets */
2656393Scg149915 break;
2666393Scg149915
2676393Scg149915 default:
2686393Scg149915 DRM_ERROR("Unknown state packet ID %d\n", id);
2696393Scg149915 return (EINVAL);
2706393Scg149915 }
2716393Scg149915
2726393Scg149915 return (0);
2736393Scg149915 }
2746393Scg149915
2756393Scg149915 static inline int
radeon_check_and_fixup_packet3(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf,unsigned int * cmdsz)2766393Scg149915 radeon_check_and_fixup_packet3(drm_radeon_private_t *dev_priv,
2776393Scg149915 drm_file_t *filp_priv, drm_radeon_kcmd_buffer_t *cmdbuf,
2786393Scg149915 unsigned int *cmdsz)
2796393Scg149915 {
2806393Scg149915 u32 *cmd = (u32 *)(uintptr_t)cmdbuf->buf;
2816393Scg149915 u32 offset, narrays;
2826393Scg149915 int count, i, k;
2836393Scg149915
2846393Scg149915 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
2856393Scg149915
2866393Scg149915 if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
2876393Scg149915 DRM_ERROR("Not a type 3 packet\n");
2886393Scg149915 return (EINVAL);
2896393Scg149915 }
2906393Scg149915
2916393Scg149915 if (4 * *cmdsz > cmdbuf->bufsz) {
2926393Scg149915 DRM_ERROR("Packet size larger than size of data provided\n");
2936393Scg149915 return (EINVAL);
2946393Scg149915 }
2956393Scg149915
2966393Scg149915
2976393Scg149915 switch (cmd[0] & 0xff00) {
2986393Scg149915 /* XXX Are there old drivers needing other packets? */
2996393Scg149915
3006393Scg149915 case RADEON_3D_DRAW_IMMD:
3016393Scg149915 case RADEON_3D_DRAW_VBUF:
3026393Scg149915 case RADEON_3D_DRAW_INDX:
3036393Scg149915 case RADEON_WAIT_FOR_IDLE:
3046393Scg149915 case RADEON_CP_NOP:
3056393Scg149915 case RADEON_3D_CLEAR_ZMASK:
3066393Scg149915 #if 0
3076393Scg149915 case RADEON_CP_NEXT_CHAR:
3086393Scg149915 case RADEON_CP_PLY_NEXTSCAN:
3096393Scg149915 case RADEON_CP_SET_SCISSORS:
3106393Scg149915 /* probably safe but will never need them? */
3116393Scg149915 #endif
3126393Scg149915 /* these packets are safe */
3136393Scg149915 break;
3146393Scg149915
3156393Scg149915 case RADEON_CP_3D_DRAW_IMMD_2:
3166393Scg149915 case RADEON_CP_3D_DRAW_VBUF_2:
3176393Scg149915 case RADEON_CP_3D_DRAW_INDX_2:
3186393Scg149915 case RADEON_3D_CLEAR_HIZ:
3196393Scg149915 /* safe but r200 only */
3206393Scg149915 if (dev_priv->microcode_version != UCODE_R200) {
3216393Scg149915 DRM_ERROR("Invalid 3d packet for r100-class chip\n");
3226393Scg149915 return (EINVAL);
3236393Scg149915 }
3246393Scg149915 break;
3256393Scg149915
3266393Scg149915 case RADEON_3D_LOAD_VBPNTR:
3276393Scg149915 count = (cmd[0] >> 16) & 0x3fff;
3286393Scg149915
3296393Scg149915 if (count > 18) { /* 12 arrays max */
3306393Scg149915 DRM_ERROR(
3316393Scg149915 "Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
3326393Scg149915 count);
3336393Scg149915 return (EINVAL);
3346393Scg149915 }
3356393Scg149915
3366393Scg149915 /* carefully check packet contents */
3376393Scg149915 narrays = cmd[1] & ~0xc000;
3386393Scg149915 k = 0;
3396393Scg149915 i = 2;
3406393Scg149915 while ((k < narrays) && (i < (count + 2))) {
3416393Scg149915 i++; /* skip attribute field */
3426393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
3436393Scg149915 filp_priv, &cmd[i])) {
3446393Scg149915 DRM_ERROR(
3456393Scg149915 "Invalid offset (k=%d i=%d) ini"
3466393Scg149915 " 3D_LOAD_VBPNTR packet.\n", k, i);
3476393Scg149915 return (EINVAL);
3486393Scg149915 }
3496393Scg149915 k++;
3506393Scg149915 i++;
3516393Scg149915 if (k == narrays)
3526393Scg149915 break;
3536393Scg149915 /* have one more to process, they come in pairs */
3546393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
3556393Scg149915 filp_priv, &cmd[i])) {
3566393Scg149915 DRM_ERROR(
3576393Scg149915 "Invalid offset (k=%d i=%d) in"
3586393Scg149915 " 3D_LOAD_VBPNTR packet.\n", k, i);
3596393Scg149915 return (EINVAL);
3606393Scg149915 }
3616393Scg149915 k++;
3626393Scg149915 i++;
3636393Scg149915 }
3646393Scg149915 /* do the counts match what we expect ? */
3656393Scg149915 if ((k != narrays) || (i != (count + 2))) {
3666393Scg149915 DRM_ERROR(
3676393Scg149915 "Malformed 3D_LOAD_VBPNTR packet"
3686393Scg149915 "(k=%d i=%d narrays=%d count+1=%d).\n",
3696393Scg149915 k, i, narrays, count + 1);
3706393Scg149915 return (EINVAL);
3716393Scg149915 }
3726393Scg149915 break;
3736393Scg149915
3746393Scg149915 case RADEON_3D_RNDR_GEN_INDX_PRIM:
3756393Scg149915 if (dev_priv->microcode_version != UCODE_R100) {
3766393Scg149915 DRM_ERROR("Invalid 3d packet for r200-class chip\n");
3776393Scg149915 return (EINVAL);
3786393Scg149915 }
3796393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
3806393Scg149915 filp_priv, &cmd[1])) {
3816393Scg149915 DRM_ERROR("Invalid rndr_gen_indx offset\n");
3826393Scg149915 return (EINVAL);
3836393Scg149915 }
3846393Scg149915 break;
3856393Scg149915
3866393Scg149915 case RADEON_CP_INDX_BUFFER:
3876393Scg149915 if (dev_priv->microcode_version != UCODE_R200) {
3886393Scg149915 DRM_ERROR("Invalid 3d packet for r100-class chip\n");
3896393Scg149915 return (EINVAL);
3906393Scg149915 }
3916393Scg149915 if ((cmd[1] & 0x8000ffff) != 0x80000810) {
3926393Scg149915 DRM_ERROR(
3936393Scg149915 "Invalid indx_buffer reg address %08X\n", cmd[1]);
3946393Scg149915 return (EINVAL);
3956393Scg149915 }
3966393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
3976393Scg149915 filp_priv, &cmd[2])) {
3986393Scg149915 DRM_ERROR(
3996393Scg149915 "Invalid indx_buffer offset is %08X\n", cmd[2]);
4006393Scg149915 return (EINVAL);
4016393Scg149915 }
4026393Scg149915 break;
4036393Scg149915
4046393Scg149915 case RADEON_CNTL_HOSTDATA_BLT:
4056393Scg149915 case RADEON_CNTL_PAINT_MULTI:
4066393Scg149915 case RADEON_CNTL_BITBLT_MULTI:
4076393Scg149915 /* MSB of opcode: next DWORD GUI_CNTL */
4086393Scg149915 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
4096393Scg149915 RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
4106393Scg149915 offset = cmd[2] << 10;
4116393Scg149915 if (radeon_check_and_fixup_offset
4126393Scg149915 (dev_priv, filp_priv, &offset)) {
4136393Scg149915 DRM_ERROR("Invalid first packet offset\n");
4146393Scg149915 return (EINVAL);
4156393Scg149915 }
4166393Scg149915 cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
4176393Scg149915 }
4186393Scg149915
4196393Scg149915 if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
4206393Scg149915 (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
4216393Scg149915 offset = cmd[3] << 10;
4226393Scg149915 if (radeon_check_and_fixup_offset
4236393Scg149915 (dev_priv, filp_priv, &offset)) {
4246393Scg149915 DRM_ERROR("Invalid second packet offset\n");
4256393Scg149915 return (EINVAL);
4266393Scg149915 }
4276393Scg149915 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
4286393Scg149915 }
4296393Scg149915 break;
4306393Scg149915
4316393Scg149915 default:
4326393Scg149915 DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
4336393Scg149915 return (EINVAL);
4346393Scg149915 }
4356393Scg149915
4366393Scg149915 return (0);
4376393Scg149915 }
4386393Scg149915
4396393Scg149915 /*
4406393Scg149915 * CP hardware state programming functions
4416393Scg149915 */
4426393Scg149915
radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,drm_clip_rect_t * box)4436393Scg149915 static inline void radeon_emit_clip_rect(drm_radeon_private_t *dev_priv,
4446393Scg149915 drm_clip_rect_t *box)
4456393Scg149915 {
4466393Scg149915 RING_LOCALS;
4476393Scg149915
4486393Scg149915 DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
4496393Scg149915 box->x1, box->y1, box->x2, box->y2);
4506393Scg149915
4516393Scg149915 BEGIN_RING(4);
4526393Scg149915 OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
4536393Scg149915 OUT_RING((box->y1 << 16) | box->x1);
4546393Scg149915 OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
4556393Scg149915 OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
4566393Scg149915 ADVANCE_RING();
4576393Scg149915 }
4586393Scg149915
4596393Scg149915 /* Emit 1.1 state */
radeon_emit_state(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_context_regs_t * ctx,drm_radeon_texture_regs_t * tex,unsigned int dirty)4606393Scg149915 static int radeon_emit_state(drm_radeon_private_t *dev_priv,
4616393Scg149915 drm_file_t *filp_priv, drm_radeon_context_regs_t *ctx,
4626393Scg149915 drm_radeon_texture_regs_t *tex, unsigned int dirty)
4636393Scg149915 {
4646393Scg149915 RING_LOCALS;
4656393Scg149915 DRM_DEBUG("dirty=0x%08x\n", dirty);
4666393Scg149915
4676393Scg149915 if (dirty & RADEON_UPLOAD_CONTEXT) {
4686393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
4696393Scg149915 &ctx->rb3d_depthoffset)) {
4706393Scg149915 DRM_ERROR("Invalid depth buffer offset\n");
4716393Scg149915 return (EINVAL);
4726393Scg149915 }
4736393Scg149915
4746393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
4756393Scg149915 &ctx->rb3d_coloroffset)) {
4766393Scg149915 DRM_ERROR("Invalid depth buffer offset\n");
4776393Scg149915 return (EINVAL);
4786393Scg149915 }
4796393Scg149915
4806393Scg149915 BEGIN_RING(14);
4816393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
4826393Scg149915 OUT_RING(ctx->pp_misc);
4836393Scg149915 OUT_RING(ctx->pp_fog_color);
4846393Scg149915 OUT_RING(ctx->re_solid_color);
4856393Scg149915 OUT_RING(ctx->rb3d_blendcntl);
4866393Scg149915 OUT_RING(ctx->rb3d_depthoffset);
4876393Scg149915 OUT_RING(ctx->rb3d_depthpitch);
4886393Scg149915 OUT_RING(ctx->rb3d_zstencilcntl);
4896393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
4906393Scg149915 OUT_RING(ctx->pp_cntl);
4916393Scg149915 OUT_RING(ctx->rb3d_cntl);
4926393Scg149915 OUT_RING(ctx->rb3d_coloroffset);
4936393Scg149915 OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
4946393Scg149915 OUT_RING(ctx->rb3d_colorpitch);
4956393Scg149915 ADVANCE_RING();
4966393Scg149915 }
4976393Scg149915
4986393Scg149915 if (dirty & RADEON_UPLOAD_VERTFMT) {
4996393Scg149915 BEGIN_RING(2);
5006393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
5016393Scg149915 OUT_RING(ctx->se_coord_fmt);
5026393Scg149915 ADVANCE_RING();
5036393Scg149915 }
5046393Scg149915
5056393Scg149915 if (dirty & RADEON_UPLOAD_LINE) {
5066393Scg149915 BEGIN_RING(5);
5076393Scg149915 OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
5086393Scg149915 OUT_RING(ctx->re_line_pattern);
5096393Scg149915 OUT_RING(ctx->re_line_state);
5106393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
5116393Scg149915 OUT_RING(ctx->se_line_width);
5126393Scg149915 ADVANCE_RING();
5136393Scg149915 }
5146393Scg149915
5156393Scg149915 if (dirty & RADEON_UPLOAD_BUMPMAP) {
5166393Scg149915 BEGIN_RING(5);
5176393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
5186393Scg149915 OUT_RING(ctx->pp_lum_matrix);
5196393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
5206393Scg149915 OUT_RING(ctx->pp_rot_matrix_0);
5216393Scg149915 OUT_RING(ctx->pp_rot_matrix_1);
5226393Scg149915 ADVANCE_RING();
5236393Scg149915 }
5246393Scg149915
5256393Scg149915 if (dirty & RADEON_UPLOAD_MASKS) {
5266393Scg149915 BEGIN_RING(4);
5276393Scg149915 OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
5286393Scg149915 OUT_RING(ctx->rb3d_stencilrefmask);
5296393Scg149915 OUT_RING(ctx->rb3d_ropcntl);
5306393Scg149915 OUT_RING(ctx->rb3d_planemask);
5316393Scg149915 ADVANCE_RING();
5326393Scg149915 }
5336393Scg149915
5346393Scg149915 if (dirty & RADEON_UPLOAD_VIEWPORT) {
5356393Scg149915 BEGIN_RING(7);
5366393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
5376393Scg149915 OUT_RING(ctx->se_vport_xscale);
5386393Scg149915 OUT_RING(ctx->se_vport_xoffset);
5396393Scg149915 OUT_RING(ctx->se_vport_yscale);
5406393Scg149915 OUT_RING(ctx->se_vport_yoffset);
5416393Scg149915 OUT_RING(ctx->se_vport_zscale);
5426393Scg149915 OUT_RING(ctx->se_vport_zoffset);
5436393Scg149915 ADVANCE_RING();
5446393Scg149915 }
5456393Scg149915
5466393Scg149915 if (dirty & RADEON_UPLOAD_SETUP) {
5476393Scg149915 BEGIN_RING(4);
5486393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
5496393Scg149915 OUT_RING(ctx->se_cntl);
5506393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
5516393Scg149915 OUT_RING(ctx->se_cntl_status);
5526393Scg149915 ADVANCE_RING();
5536393Scg149915 }
5546393Scg149915
5556393Scg149915 if (dirty & RADEON_UPLOAD_MISC) {
5566393Scg149915 BEGIN_RING(2);
5576393Scg149915 OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
5586393Scg149915 OUT_RING(ctx->re_misc);
5596393Scg149915 ADVANCE_RING();
5606393Scg149915 }
5616393Scg149915
5626393Scg149915 if (dirty & RADEON_UPLOAD_TEX0) {
5636393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
5646393Scg149915 filp_priv, &tex[0].pp_txoffset)) {
5656393Scg149915 DRM_ERROR("Invalid texture offset for unit 0\n");
5666393Scg149915 return (EINVAL);
5676393Scg149915 }
5686393Scg149915
5696393Scg149915 BEGIN_RING(9);
5706393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
5716393Scg149915 OUT_RING(tex[0].pp_txfilter);
5726393Scg149915 OUT_RING(tex[0].pp_txformat);
5736393Scg149915 OUT_RING(tex[0].pp_txoffset);
5746393Scg149915 OUT_RING(tex[0].pp_txcblend);
5756393Scg149915 OUT_RING(tex[0].pp_txablend);
5766393Scg149915 OUT_RING(tex[0].pp_tfactor);
5776393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
5786393Scg149915 OUT_RING(tex[0].pp_border_color);
5796393Scg149915 ADVANCE_RING();
5806393Scg149915 }
5816393Scg149915
5826393Scg149915 if (dirty & RADEON_UPLOAD_TEX1) {
5836393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
5846393Scg149915 filp_priv, &tex[1].pp_txoffset)) {
5856393Scg149915 DRM_ERROR("Invalid texture offset for unit 1\n");
5866393Scg149915 return (EINVAL);
5876393Scg149915 }
5886393Scg149915
5896393Scg149915 BEGIN_RING(9);
5906393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
5916393Scg149915 OUT_RING(tex[1].pp_txfilter);
5926393Scg149915 OUT_RING(tex[1].pp_txformat);
5936393Scg149915 OUT_RING(tex[1].pp_txoffset);
5946393Scg149915 OUT_RING(tex[1].pp_txcblend);
5956393Scg149915 OUT_RING(tex[1].pp_txablend);
5966393Scg149915 OUT_RING(tex[1].pp_tfactor);
5976393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
5986393Scg149915 OUT_RING(tex[1].pp_border_color);
5996393Scg149915 ADVANCE_RING();
6006393Scg149915 }
6016393Scg149915
6026393Scg149915 if (dirty & RADEON_UPLOAD_TEX2) {
6036393Scg149915 if (radeon_check_and_fixup_offset(dev_priv,
6046393Scg149915 filp_priv, &tex[2].pp_txoffset)) {
6056393Scg149915 DRM_ERROR("Invalid texture offset for unit 2\n");
6066393Scg149915 return (EINVAL);
6076393Scg149915 }
6086393Scg149915
6096393Scg149915 BEGIN_RING(9);
6106393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
6116393Scg149915 OUT_RING(tex[2].pp_txfilter);
6126393Scg149915 OUT_RING(tex[2].pp_txformat);
6136393Scg149915 OUT_RING(tex[2].pp_txoffset);
6146393Scg149915 OUT_RING(tex[2].pp_txcblend);
6156393Scg149915 OUT_RING(tex[2].pp_txablend);
6166393Scg149915 OUT_RING(tex[2].pp_tfactor);
6176393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
6186393Scg149915 OUT_RING(tex[2].pp_border_color);
6196393Scg149915 ADVANCE_RING();
6206393Scg149915 }
6216393Scg149915
6226393Scg149915 return (0);
6236393Scg149915 }
6246393Scg149915
6256393Scg149915 /* Emit 1.2 state */
radeon_emit_state2(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_state_t * state)6266393Scg149915 static int radeon_emit_state2(drm_radeon_private_t *dev_priv,
6276393Scg149915 drm_file_t *filp_priv, drm_radeon_state_t *state)
6286393Scg149915 {
6296393Scg149915 RING_LOCALS;
6306393Scg149915
6316393Scg149915 if (state->dirty & RADEON_UPLOAD_ZBIAS) {
6326393Scg149915 BEGIN_RING(3);
6336393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
6346393Scg149915 OUT_RING(state->context2.se_zbias_factor);
6356393Scg149915 OUT_RING(state->context2.se_zbias_constant);
6366393Scg149915 ADVANCE_RING();
6376393Scg149915 }
6386393Scg149915
6396393Scg149915 return (radeon_emit_state(dev_priv, filp_priv,
6406393Scg149915 &state->context, state->tex, state->dirty));
6416393Scg149915 }
6426393Scg149915
6436393Scg149915 /*
6446393Scg149915 * New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
6456393Scg149915 * 1.3 cmdbuffers allow all previous state to be updated as well as
6466393Scg149915 * the tcl scalar and vector areas.
6476393Scg149915 */
6486393Scg149915 static struct {
6496393Scg149915 int start;
6506393Scg149915 int len;
6516393Scg149915 const char *name;
6526393Scg149915 } packet[RADEON_MAX_STATE_PACKETS] = {
6536393Scg149915 {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
6546393Scg149915 {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
6556393Scg149915 {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
6566393Scg149915 {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
6576393Scg149915 {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
6586393Scg149915 {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
6596393Scg149915 {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
6606393Scg149915 {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
6616393Scg149915 {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
6626393Scg149915 {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
6636393Scg149915 {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
6646393Scg149915 {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
6656393Scg149915 {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
6666393Scg149915 {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
6676393Scg149915 {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
6686393Scg149915 {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
6696393Scg149915 {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
6706393Scg149915 {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
6716393Scg149915 {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
6726393Scg149915 {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
6736393Scg149915 {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
6746393Scg149915 "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
6756393Scg149915 {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
6766393Scg149915 {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
6776393Scg149915 {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
6786393Scg149915 {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
6796393Scg149915 {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
6806393Scg149915 {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
6816393Scg149915 {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
6826393Scg149915 {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
6836393Scg149915 {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
6846393Scg149915 {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
6856393Scg149915 {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
6866393Scg149915 {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
6876393Scg149915 {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
6886393Scg149915 {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
6896393Scg149915 {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
6906393Scg149915 {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
6916393Scg149915 {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
6926393Scg149915 {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
6936393Scg149915 {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
6946393Scg149915 {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
6956393Scg149915 {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
6966393Scg149915 {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
6976393Scg149915 {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
6986393Scg149915 {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
6996393Scg149915 {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
7006393Scg149915 {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
7016393Scg149915 {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
7026393Scg149915 {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
7036393Scg149915 {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
7046393Scg149915 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
7056393Scg149915 {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
7066393Scg149915 {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
7076393Scg149915 {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
7086393Scg149915 {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
7096393Scg149915 {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
7106393Scg149915 {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
7116393Scg149915 {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
7126393Scg149915 {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
7136393Scg149915 {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
7146393Scg149915 {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
7156393Scg149915 {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
7166393Scg149915 "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
7176393Scg149915 {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
7186393Scg149915 {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
7196393Scg149915 {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
7206393Scg149915 {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
7216393Scg149915 {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
7226393Scg149915 {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
7236393Scg149915 {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
7246393Scg149915 {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
7256393Scg149915 {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
7266393Scg149915 {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
7276393Scg149915 {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
7286393Scg149915 {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
7296393Scg149915 {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
7306393Scg149915 {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
7316393Scg149915 {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
7326393Scg149915 {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
7336393Scg149915 {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
7346393Scg149915 {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
7356393Scg149915 {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
7366393Scg149915 {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
7376393Scg149915 {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
7386393Scg149915 {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
7396393Scg149915 {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
7406393Scg149915 {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
7416393Scg149915 {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
7426393Scg149915 {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
7436393Scg149915 {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
7446393Scg149915 {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
7456393Scg149915 {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
7466393Scg149915 {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
7476393Scg149915 {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
7486393Scg149915 {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
7496393Scg149915 {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
7506393Scg149915 {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
7516393Scg149915 };
7526393Scg149915
7536393Scg149915 /*
7546393Scg149915 * Performance monitoring functions
7556393Scg149915 */
7566393Scg149915
radeon_clear_box(drm_radeon_private_t * dev_priv,int x,int y,int w,int h,int r,int g,int b)7576393Scg149915 static void radeon_clear_box(drm_radeon_private_t *dev_priv,
7586393Scg149915 int x, int y, int w, int h, int r, int g, int b)
7596393Scg149915 {
7606393Scg149915 u32 color;
7616393Scg149915 RING_LOCALS;
7626393Scg149915
7636393Scg149915 x += dev_priv->sarea_priv->boxes[0].x1;
7646393Scg149915 y += dev_priv->sarea_priv->boxes[0].y1;
7656393Scg149915
7666393Scg149915 switch (dev_priv->color_fmt) {
7676393Scg149915 case RADEON_COLOR_FORMAT_RGB565:
7686393Scg149915 color = (((r & 0xf8) << 8) |
7696393Scg149915 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
7706393Scg149915 break;
7716393Scg149915 case RADEON_COLOR_FORMAT_ARGB8888:
7726393Scg149915 default:
7736393Scg149915 color = (((0xfful) << 24) | (r << 16) | (g << 8) | b);
7746393Scg149915 break;
7756393Scg149915 }
7766393Scg149915
7776393Scg149915 BEGIN_RING(4);
7786393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
7796393Scg149915 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
7806393Scg149915 OUT_RING(0xffffffff);
7816393Scg149915 ADVANCE_RING();
7826393Scg149915
7836393Scg149915 BEGIN_RING(6);
7846393Scg149915
7856393Scg149915 OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
7866393Scg149915 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
7876393Scg149915 RADEON_GMC_BRUSH_SOLID_COLOR |
7886393Scg149915 (dev_priv->color_fmt << 8) |
7896393Scg149915 RADEON_GMC_SRC_DATATYPE_COLOR |
7906393Scg149915 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
7916393Scg149915
7926393Scg149915 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
7936393Scg149915 OUT_RING(dev_priv->front_pitch_offset);
7946393Scg149915 } else {
7956393Scg149915 OUT_RING(dev_priv->back_pitch_offset);
7966393Scg149915 }
7976393Scg149915
7986393Scg149915 OUT_RING(color);
7996393Scg149915
8006393Scg149915 OUT_RING((x << 16) | y);
8016393Scg149915 OUT_RING((w << 16) | h);
8026393Scg149915
8036393Scg149915 ADVANCE_RING();
8046393Scg149915 }
8056393Scg149915
radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)8066393Scg149915 static void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv)
8076393Scg149915 {
8086393Scg149915 /*
8096393Scg149915 * Collapse various things into a wait flag -- trying to
8106393Scg149915 * guess if userspase slept -- better just to have them tell us.
8116393Scg149915 */
8126393Scg149915 if (dev_priv->stats.last_frame_reads > 1 ||
8136393Scg149915 dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
8146393Scg149915 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
8156393Scg149915 }
8166393Scg149915
8176393Scg149915 if (dev_priv->stats.freelist_loops) {
8186393Scg149915 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
8196393Scg149915 }
8206393Scg149915
8216393Scg149915 /* Purple box for page flipping */
8226393Scg149915 if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
8236393Scg149915 radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
8246393Scg149915
8256393Scg149915 /* Red box if we have to wait for idle at any point */
8266393Scg149915 if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
8276393Scg149915 radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
8286393Scg149915
8296393Scg149915 /* Blue box: lost context? */
8306393Scg149915
8316393Scg149915 /* Yellow box for texture swaps */
8326393Scg149915 if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
8336393Scg149915 radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
8346393Scg149915
8356393Scg149915 /* Green box if hardware never idles (as far as we can tell) */
8366393Scg149915 if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
8376393Scg149915 radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
8386393Scg149915
8396393Scg149915 /*
8406393Scg149915 * Draw bars indicating number of buffers allocated
8416393Scg149915 * (not a great measure, easily confused)
8426393Scg149915 */
8436393Scg149915 if (dev_priv->stats.requested_bufs) {
8446393Scg149915 if (dev_priv->stats.requested_bufs > 100)
8456393Scg149915 dev_priv->stats.requested_bufs = 100;
8466393Scg149915
8476393Scg149915 radeon_clear_box(dev_priv, 4, 16,
8486393Scg149915 dev_priv->stats.requested_bufs, 4, 196, 128, 128);
8496393Scg149915 }
8506393Scg149915
8516393Scg149915 (void) memset(&dev_priv->stats, 0, sizeof (dev_priv->stats));
8526393Scg149915
8536393Scg149915 }
8546393Scg149915
8556393Scg149915 /*
8566393Scg149915 * CP command dispatch functions
8576393Scg149915 */
8586393Scg149915
radeon_cp_dispatch_clear(drm_device_t * dev,drm_radeon_clear_t * clear,drm_radeon_clear_rect_t * depth_boxes)8596393Scg149915 static void radeon_cp_dispatch_clear(drm_device_t *dev,
8606393Scg149915 drm_radeon_clear_t *clear, drm_radeon_clear_rect_t *depth_boxes)
8616393Scg149915 {
8626393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
8636393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
8646393Scg149915 drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
8656393Scg149915 int nbox = sarea_priv->nbox;
8666393Scg149915 drm_clip_rect_t *pbox = sarea_priv->boxes;
8676393Scg149915 unsigned int flags = clear->flags;
8686393Scg149915 u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
8696393Scg149915 int i;
8706393Scg149915 RING_LOCALS;
8716393Scg149915 DRM_DEBUG("flags = 0x%x\n", flags);
8726393Scg149915
8736393Scg149915 dev_priv->stats.clears++;
8746393Scg149915
8756393Scg149915 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
8766393Scg149915 unsigned int tmp = flags;
8776393Scg149915
8786393Scg149915 flags &= ~(RADEON_FRONT | RADEON_BACK);
8796393Scg149915 if (tmp & RADEON_FRONT)
8806393Scg149915 flags |= RADEON_BACK;
8816393Scg149915 if (tmp & RADEON_BACK)
8826393Scg149915 flags |= RADEON_FRONT;
8836393Scg149915 }
8846393Scg149915
8856393Scg149915 if (flags & (RADEON_FRONT | RADEON_BACK)) {
8866393Scg149915
8876393Scg149915 BEGIN_RING(4);
8886393Scg149915
8896393Scg149915 /*
8906393Scg149915 * Ensure the 3D stream is idle before doing a
8916393Scg149915 * 2D fill to clear the front or back buffer.
8926393Scg149915 */
8936393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
8946393Scg149915
8956393Scg149915 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
8966393Scg149915 OUT_RING(clear->color_mask);
8976393Scg149915
8986393Scg149915 ADVANCE_RING();
8996393Scg149915
9006393Scg149915 /* Make sure we restore the 3D state next time. */
9016393Scg149915 dev_priv->sarea_priv->ctx_owner = 0;
9026393Scg149915
9036393Scg149915 for (i = 0; i < nbox; i++) {
9046393Scg149915 int x = pbox[i].x1;
9056393Scg149915 int y = pbox[i].y1;
9066393Scg149915 int w = pbox[i].x2 - x;
9076393Scg149915 int h = pbox[i].y2 - y;
9086393Scg149915
9096393Scg149915 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
9106393Scg149915 x, y, w, h, flags);
9116393Scg149915
9126393Scg149915 if (flags & RADEON_FRONT) {
9136393Scg149915 BEGIN_RING(6);
9146393Scg149915
9156393Scg149915 OUT_RING(CP_PACKET3
9166393Scg149915 (RADEON_CNTL_PAINT_MULTI, 4));
9176393Scg149915 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
9186393Scg149915 RADEON_GMC_BRUSH_SOLID_COLOR |
9196393Scg149915 (dev_priv-> color_fmt << 8) |
9206393Scg149915 RADEON_GMC_SRC_DATATYPE_COLOR |
9216393Scg149915 RADEON_ROP3_P |
9226393Scg149915 RADEON_GMC_CLR_CMP_CNTL_DIS);
9236393Scg149915
9246393Scg149915 OUT_RING(dev_priv->front_pitch_offset);
9256393Scg149915 OUT_RING(clear->clear_color);
9266393Scg149915
9276393Scg149915 OUT_RING((x << 16) | y);
9286393Scg149915 OUT_RING((w << 16) | h);
9296393Scg149915
9306393Scg149915 ADVANCE_RING();
9316393Scg149915 }
9326393Scg149915
9336393Scg149915 if (flags & RADEON_BACK) {
9346393Scg149915 BEGIN_RING(6);
9356393Scg149915
9366393Scg149915 OUT_RING(CP_PACKET3
9376393Scg149915 (RADEON_CNTL_PAINT_MULTI, 4));
9386393Scg149915 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
9396393Scg149915 RADEON_GMC_BRUSH_SOLID_COLOR |
9406393Scg149915 (dev_priv-> color_fmt << 8) |
9416393Scg149915 RADEON_GMC_SRC_DATATYPE_COLOR |
9426393Scg149915 RADEON_ROP3_P |
9436393Scg149915 RADEON_GMC_CLR_CMP_CNTL_DIS);
9446393Scg149915
9456393Scg149915 OUT_RING(dev_priv->back_pitch_offset);
9466393Scg149915 OUT_RING(clear->clear_color);
9476393Scg149915
9486393Scg149915 OUT_RING((x << 16) | y);
9496393Scg149915 OUT_RING((w << 16) | h);
9506393Scg149915
9516393Scg149915 ADVANCE_RING();
9526393Scg149915 }
9536393Scg149915 }
9546393Scg149915 }
9556393Scg149915
9566393Scg149915 /* hyper z clear */
9576393Scg149915 /*
9586393Scg149915 * no docs available, based on reverse engeneering
9596393Scg149915 * by Stephane Marchesin
9606393Scg149915 */
9616393Scg149915 if ((flags & (RADEON_DEPTH | RADEON_STENCIL)) &&
9626393Scg149915 (flags & RADEON_CLEAR_FASTZ)) {
9636393Scg149915
9646393Scg149915 int i;
9656393Scg149915 int depthpixperline =
9666393Scg149915 dev_priv->depth_fmt ==
9676393Scg149915 RADEON_DEPTH_FORMAT_16BIT_INT_Z ?
9686393Scg149915 (dev_priv->depth_pitch / 2) :
9696393Scg149915 (dev_priv-> depth_pitch / 4);
9706393Scg149915
9716393Scg149915 u32 clearmask;
9726393Scg149915
9736393Scg149915 u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
9746393Scg149915 ((clear->depth_mask & 0xff) << 24);
9756393Scg149915
9766393Scg149915 /*
9776393Scg149915 * Make sure we restore the 3D state next time.
9786393Scg149915 * we haven't touched any "normal" state - still
9796393Scg149915 * need this?
9806393Scg149915 */
9816393Scg149915 dev_priv->sarea_priv->ctx_owner = 0;
9826393Scg149915
9836393Scg149915 if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
9846393Scg149915 (flags & RADEON_USE_HIERZ)) {
9856393Scg149915 /* FIXME : reverse engineer that for Rx00 cards */
9866393Scg149915 /*
9876393Scg149915 * FIXME : the mask supposedly contains low-res
9886393Scg149915 * z values. So can't set just to the max (0xff?
9896393Scg149915 * or actually 0x3fff?), need to take z clear
9906393Scg149915 * value into account?
9916393Scg149915 */
9926393Scg149915 /*
9936393Scg149915 * pattern seems to work for r100, though get
9946393Scg149915 * slight rendering errors with glxgears. If
9956393Scg149915 * hierz is not enabled for r100, only 4 bits
9966393Scg149915 * which indicate clear (15,16,31,32, all zero)
9976393Scg149915 * matter, the other ones are ignored, and the
9986393Scg149915 * same clear mask can be used. That's very
9996393Scg149915 * different behaviour than R200 which needs
10006393Scg149915 * different clear mask and different number
10016393Scg149915 * of tiles to clear if hierz is enabled or not !?!
10026393Scg149915 */
10036393Scg149915 clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
10046393Scg149915 } else {
10056393Scg149915 /*
10066393Scg149915 * clear mask : chooses the clearing pattern.
10076393Scg149915 * rv250: could be used to clear only parts of macrotiles
10086393Scg149915 * (but that would get really complicated...)?
10096393Scg149915 * bit 0 and 1 (either or both of them ?!?!) are used to
10106393Scg149915 * not clear tile (or maybe one of the bits indicates if
10116393Scg149915 * the tile is compressed or not), bit 2 and 3 to not
10126393Scg149915 * clear tile 1,...,.
10136393Scg149915 * Pattern is as follows:
10146393Scg149915 * | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
10156393Scg149915 * bits -------------------------------------------------
10166393Scg149915 * | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
10176393Scg149915 * rv100: clearmask covers 2x8 4x1 tiles, but one clear
10186393Scg149915 * still covers 256 pixels ?!?
10196393Scg149915 */
10206393Scg149915 clearmask = 0x0;
10216393Scg149915 }
10226393Scg149915
10236393Scg149915 BEGIN_RING(8);
10246393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
10256393Scg149915 OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
10266393Scg149915 tempRB3D_DEPTHCLEARVALUE);
10276393Scg149915 /* what offset is this exactly ? */
10286393Scg149915 OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
10296393Scg149915 /* need ctlstat, otherwise get some strange black flickering */
10306393Scg149915 OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
10316393Scg149915 RADEON_RB3D_ZC_FLUSH_ALL);
10326393Scg149915 ADVANCE_RING();
10336393Scg149915
10346393Scg149915 for (i = 0; i < nbox; i++) {
10356393Scg149915 int tileoffset, nrtilesx, nrtilesy, j;
10366393Scg149915 /*
10376393Scg149915 * it looks like r200 needs rv-style clears, at
10386393Scg149915 * least if hierz is not enabled?
10396393Scg149915 */
10406393Scg149915 if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
10416393Scg149915 !(dev_priv->microcode_version == UCODE_R200)) {
10426393Scg149915 /*
10436393Scg149915 * FIXME : figure this out for r200 (when hierz
10446393Scg149915 * is enabled). Or maybe r200 actually doesn't
10456393Scg149915 * need to put the low-res z value into the tile
10466393Scg149915 * cache like r100, but just needs to clear the
10476393Scg149915 * hi-level z-buffer? Works for R100, both with
10486393Scg149915 * hierz and without.R100 seems to operate on
10496393Scg149915 * 2x1 8x8 tiles, but... odd: offset/nrtiles
10506393Scg149915 * need to be 64 pix (4 blocka) aligned?
10516393Scg149915 * Potentially problematic with resolutions
10526393Scg149915 * which are not 64 pix aligned?
10536393Scg149915 */
10546393Scg149915 tileoffset =
10556393Scg149915 ((pbox[i].y1 >> 3) * depthpixperline +
10566393Scg149915 pbox[i].x1) >> 6;
10576393Scg149915 nrtilesx =
10586393Scg149915 ((pbox[i].x2 & ~63) -
10596393Scg149915 (pbox[i].x1 & ~63)) >> 4;
10606393Scg149915 nrtilesy =
10616393Scg149915 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
10626393Scg149915 for (j = 0; j <= nrtilesy; j++) {
10636393Scg149915 BEGIN_RING(4);
10646393Scg149915 OUT_RING(CP_PACKET3
10656393Scg149915 (RADEON_3D_CLEAR_ZMASK, 2));
10666393Scg149915 /* first tile */
10676393Scg149915 OUT_RING(tileoffset * 8);
10686393Scg149915 /* the number of tiles to clear */
10696393Scg149915 OUT_RING(nrtilesx + 4);
10706393Scg149915 /*
10716393Scg149915 * clear mask :
10726393Scg149915 * chooses the clearing pattern.
10736393Scg149915 */
10746393Scg149915 OUT_RING(clearmask);
10756393Scg149915 ADVANCE_RING();
10766393Scg149915 tileoffset += depthpixperline >> 6;
10776393Scg149915 }
10786393Scg149915 } else if (dev_priv->microcode_version == UCODE_R200) {
10796393Scg149915 /* works for rv250. */
10806393Scg149915 /*
10816393Scg149915 * find first macro tile
10826393Scg149915 * (8x2 4x4 z-pixels on rv250)
10836393Scg149915 */
10846393Scg149915 tileoffset =
10856393Scg149915 ((pbox[i].y1 >> 3) * depthpixperline +
10866393Scg149915 pbox[i].x1) >> 5;
10876393Scg149915 nrtilesx =
10886393Scg149915 (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
10896393Scg149915 nrtilesy =
10906393Scg149915 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
10916393Scg149915 for (j = 0; j <= nrtilesy; j++) {
10926393Scg149915 BEGIN_RING(4);
10936393Scg149915 OUT_RING(CP_PACKET3
10946393Scg149915 (RADEON_3D_CLEAR_ZMASK, 2));
10956393Scg149915 /* first tile */
10966393Scg149915 /*
10976393Scg149915 * judging by the first tile
10986393Scg149915 * offset needed, could possibly
10996393Scg149915 * directly address/clear 4x4
11006393Scg149915 * tiles instead of 8x2 * 4x4
11016393Scg149915 * macro tiles, though would
11026393Scg149915 * still need clear mask for
11036393Scg149915 * right/bottom if truely 4x4
11046393Scg149915 * granularity is desired ?
11056393Scg149915 */
11066393Scg149915 OUT_RING(tileoffset * 16);
11076393Scg149915 /* the number of tiles to clear */
11086393Scg149915 OUT_RING(nrtilesx + 1);
11096393Scg149915 /*
11106393Scg149915 * clear mask :
11116393Scg149915 * chooses the clearing pattern.
11126393Scg149915 */
11136393Scg149915 OUT_RING(clearmask);
11146393Scg149915 ADVANCE_RING();
11156393Scg149915 tileoffset += depthpixperline >> 5;
11166393Scg149915 }
11176393Scg149915 } else { /* rv 100 */
11186393Scg149915 /* rv100 might not need 64 pix alignment */
11196393Scg149915 /* offsets are, hmm, weird */
11206393Scg149915 tileoffset =
11216393Scg149915 ((pbox[i].y1 >> 4) * depthpixperline +
11226393Scg149915 pbox[i].x1) >> 6;
11236393Scg149915 nrtilesx =
11246393Scg149915 ((pbox[i].x2 & ~63) -
11256393Scg149915 (pbox[i].x1 & ~63)) >> 4;
11266393Scg149915 nrtilesy =
11276393Scg149915 (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
11286393Scg149915 for (j = 0; j <= nrtilesy; j++) {
11296393Scg149915 BEGIN_RING(4);
11306393Scg149915 OUT_RING(CP_PACKET3
11316393Scg149915 (RADEON_3D_CLEAR_ZMASK, 2));
11326393Scg149915 OUT_RING(tileoffset * 128);
11336393Scg149915 /* the number of tiles to clear */
11346393Scg149915 OUT_RING(nrtilesx + 4);
11356393Scg149915 /*
11366393Scg149915 * clear mask :
11376393Scg149915 * chooses the clearing pattern.
11386393Scg149915 */
11396393Scg149915 OUT_RING(clearmask);
11406393Scg149915 ADVANCE_RING();
11416393Scg149915 tileoffset += depthpixperline >> 6;
11426393Scg149915 }
11436393Scg149915 }
11446393Scg149915 }
11456393Scg149915
11466393Scg149915 /* TODO don't always clear all hi-level z tiles */
11476393Scg149915 if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
11486393Scg149915 (dev_priv->microcode_version == UCODE_R200) &&
11496393Scg149915 (flags & RADEON_USE_HIERZ))
11506393Scg149915 /*
11516393Scg149915 * r100 and cards without hierarchical z-buffer
11526393Scg149915 * have no high-level z-buffer
11536393Scg149915 */
11546393Scg149915 /*
11556393Scg149915 * FIXME : the mask supposedly contains low-res
11566393Scg149915 * z values. So can't set just to the max (0xff?
11576393Scg149915 * or actually 0x3fff?), need to take z clear value
11586393Scg149915 * into account?
11596393Scg149915 */
11606393Scg149915 {
11616393Scg149915 BEGIN_RING(4);
11626393Scg149915 OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
11636393Scg149915 OUT_RING(0x0); /* First tile */
11646393Scg149915 OUT_RING(0x3cc0);
11656393Scg149915 OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
11666393Scg149915 ADVANCE_RING();
11676393Scg149915 }
11686393Scg149915 }
11696393Scg149915
11706393Scg149915 /*
11716393Scg149915 * We have to clear the depth and/or stencil buffers by
11726393Scg149915 * rendering a quad into just those buffers. Thus, we have to
11736393Scg149915 * make sure the 3D engine is configured correctly.
11746393Scg149915 */
11756393Scg149915 else if ((dev_priv->microcode_version == UCODE_R200) &&
11766393Scg149915 (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
11776393Scg149915
11786393Scg149915 int tempPP_CNTL;
11796393Scg149915 int tempRE_CNTL;
11806393Scg149915 int tempRB3D_CNTL;
11816393Scg149915 int tempRB3D_ZSTENCILCNTL;
11826393Scg149915 int tempRB3D_STENCILREFMASK;
11836393Scg149915 int tempRB3D_PLANEMASK;
11846393Scg149915 int tempSE_CNTL;
11856393Scg149915 int tempSE_VTE_CNTL;
11866393Scg149915 int tempSE_VTX_FMT_0;
11876393Scg149915 int tempSE_VTX_FMT_1;
11886393Scg149915 int tempSE_VAP_CNTL;
11896393Scg149915 int tempRE_AUX_SCISSOR_CNTL;
11906393Scg149915
11916393Scg149915 tempPP_CNTL = 0;
11926393Scg149915 tempRE_CNTL = 0;
11936393Scg149915
11946393Scg149915 tempRB3D_CNTL = depth_clear->rb3d_cntl;
11956393Scg149915
11966393Scg149915 tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
11976393Scg149915 tempRB3D_STENCILREFMASK = 0x0;
11986393Scg149915
11996393Scg149915 tempSE_CNTL = depth_clear->se_cntl;
12006393Scg149915
12016393Scg149915 /* Disable TCL */
12026393Scg149915
12036393Scg149915 tempSE_VAP_CNTL =
12046393Scg149915 (/* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
12056393Scg149915 (0x9 << SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
12066393Scg149915
12076393Scg149915 tempRB3D_PLANEMASK = 0x0;
12086393Scg149915
12096393Scg149915 tempRE_AUX_SCISSOR_CNTL = 0x0;
12106393Scg149915
12116393Scg149915 tempSE_VTE_CNTL =
12126393Scg149915 SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
12136393Scg149915
12146393Scg149915 /* Vertex format (X, Y, Z, W) */
12156393Scg149915 tempSE_VTX_FMT_0 =
12166393Scg149915 SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
12176393Scg149915 SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
12186393Scg149915 tempSE_VTX_FMT_1 = 0x0;
12196393Scg149915
12206393Scg149915 /*
12216393Scg149915 * Depth buffer specific enables
12226393Scg149915 */
12236393Scg149915 if (flags & RADEON_DEPTH) {
12246393Scg149915 /* Enable depth buffer */
12256393Scg149915 tempRB3D_CNTL |= RADEON_Z_ENABLE;
12266393Scg149915 } else {
12276393Scg149915 /* Disable depth buffer */
12286393Scg149915 tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
12296393Scg149915 }
12306393Scg149915
12316393Scg149915 /*
12326393Scg149915 * Stencil buffer specific enables
12336393Scg149915 */
12346393Scg149915 if (flags & RADEON_STENCIL) {
12356393Scg149915 tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
12366393Scg149915 tempRB3D_STENCILREFMASK = clear->depth_mask;
12376393Scg149915 } else {
12386393Scg149915 tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
12396393Scg149915 tempRB3D_STENCILREFMASK = 0x00000000;
12406393Scg149915 }
12416393Scg149915
12426393Scg149915 if (flags & RADEON_USE_COMP_ZBUF) {
12436393Scg149915 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
12446393Scg149915 RADEON_Z_DECOMPRESSION_ENABLE;
12456393Scg149915 }
12466393Scg149915 if (flags & RADEON_USE_HIERZ) {
12476393Scg149915 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
12486393Scg149915 }
12496393Scg149915
12506393Scg149915 BEGIN_RING(26);
12516393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
12526393Scg149915
12536393Scg149915 OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
12546393Scg149915 OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
12556393Scg149915 OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
12566393Scg149915 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
12576393Scg149915 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
12586393Scg149915 tempRB3D_STENCILREFMASK);
12596393Scg149915 OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
12606393Scg149915 OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
12616393Scg149915 OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
12626393Scg149915 OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
12636393Scg149915 OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
12646393Scg149915 OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
12656393Scg149915 OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
12666393Scg149915 ADVANCE_RING();
12676393Scg149915
12686393Scg149915 /* Make sure we restore the 3D state next time. */
12696393Scg149915 dev_priv->sarea_priv->ctx_owner = 0;
12706393Scg149915
12716393Scg149915 for (i = 0; i < nbox; i++) {
12726393Scg149915
12736393Scg149915 /*
12746393Scg149915 * Funny that this should be required --
12756393Scg149915 * sets top-left?
12766393Scg149915 */
12776393Scg149915 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
12786393Scg149915
12796393Scg149915 BEGIN_RING(14);
12806393Scg149915 OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
12816393Scg149915 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
12826393Scg149915 RADEON_PRIM_WALK_RING |
12836393Scg149915 (3 << RADEON_NUM_VERTICES_SHIFT)));
12846393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
12856393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
12866393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
12876393Scg149915 OUT_RING(0x3f800000);
12886393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
12896393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
12906393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
12916393Scg149915 OUT_RING(0x3f800000);
12926393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
12936393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
12946393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
12956393Scg149915 OUT_RING(0x3f800000);
12966393Scg149915 ADVANCE_RING();
12976393Scg149915 }
12986393Scg149915 } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
12996393Scg149915
13006393Scg149915 int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
13016393Scg149915
13026393Scg149915 rb3d_cntl = depth_clear->rb3d_cntl;
13036393Scg149915
13046393Scg149915 if (flags & RADEON_DEPTH) {
13056393Scg149915 rb3d_cntl |= RADEON_Z_ENABLE;
13066393Scg149915 } else {
13076393Scg149915 rb3d_cntl &= ~RADEON_Z_ENABLE;
13086393Scg149915 }
13096393Scg149915
13106393Scg149915 if (flags & RADEON_STENCIL) {
13116393Scg149915 rb3d_cntl |= RADEON_STENCIL_ENABLE;
13126393Scg149915
13136393Scg149915 /* misnamed field */
13146393Scg149915 rb3d_stencilrefmask = clear->depth_mask;
13156393Scg149915
13166393Scg149915 } else {
13176393Scg149915 rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
13186393Scg149915 rb3d_stencilrefmask = 0x00000000;
13196393Scg149915 }
13206393Scg149915
13216393Scg149915 if (flags & RADEON_USE_COMP_ZBUF) {
13226393Scg149915 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
13236393Scg149915 RADEON_Z_DECOMPRESSION_ENABLE;
13246393Scg149915 }
13256393Scg149915 if (flags & RADEON_USE_HIERZ) {
13266393Scg149915 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
13276393Scg149915 }
13286393Scg149915
13296393Scg149915 BEGIN_RING(13);
13306393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
13316393Scg149915
13326393Scg149915 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
13336393Scg149915 OUT_RING(0x00000000);
13346393Scg149915 OUT_RING(rb3d_cntl);
13356393Scg149915
13366393Scg149915 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
13376393Scg149915 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
13386393Scg149915 OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
13396393Scg149915 OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
13406393Scg149915 ADVANCE_RING();
13416393Scg149915
13426393Scg149915 /* Make sure we restore the 3D state next time. */
13436393Scg149915 dev_priv->sarea_priv->ctx_owner = 0;
13446393Scg149915
13456393Scg149915 for (i = 0; i < nbox; i++) {
13466393Scg149915
13476393Scg149915 /*
13486393Scg149915 * Funny that this should be required --
13496393Scg149915 * sets top-left?
13506393Scg149915 */
13516393Scg149915 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
13526393Scg149915
13536393Scg149915 BEGIN_RING(15);
13546393Scg149915
13556393Scg149915 OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
13566393Scg149915 OUT_RING(RADEON_VTX_Z_PRESENT |
13576393Scg149915 RADEON_VTX_PKCOLOR_PRESENT);
13586393Scg149915 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
13596393Scg149915 RADEON_PRIM_WALK_RING |
13606393Scg149915 RADEON_MAOS_ENABLE |
13616393Scg149915 RADEON_VTX_FMT_RADEON_MODE |
13626393Scg149915 (3 << RADEON_NUM_VERTICES_SHIFT)));
13636393Scg149915
13646393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
13656393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
13666393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
13676393Scg149915 OUT_RING(0x0);
13686393Scg149915
13696393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
13706393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
13716393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
13726393Scg149915 OUT_RING(0x0);
13736393Scg149915
13746393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
13756393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
13766393Scg149915 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
13776393Scg149915 OUT_RING(0x0);
13786393Scg149915
13796393Scg149915 ADVANCE_RING();
13806393Scg149915 }
13816393Scg149915 }
13826393Scg149915
13836393Scg149915 /*
13846393Scg149915 * Increment the clear counter. The client-side 3D driver must
13856393Scg149915 * wait on this value before performing the clear ioctl. We
13866393Scg149915 * need this because the card's so damned fast...
13876393Scg149915 */
13886393Scg149915 dev_priv->sarea_priv->last_clear++;
13896393Scg149915
13906393Scg149915 BEGIN_RING(4);
13916393Scg149915
13926393Scg149915 RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
13936393Scg149915 RADEON_WAIT_UNTIL_IDLE();
13946393Scg149915
13956393Scg149915 ADVANCE_RING();
13966393Scg149915 }
13976393Scg149915
radeon_cp_dispatch_swap(drm_device_t * dev)13986393Scg149915 static void radeon_cp_dispatch_swap(drm_device_t *dev)
13996393Scg149915 {
14006393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
14016393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
14026393Scg149915 int nbox = sarea_priv->nbox;
14036393Scg149915 drm_clip_rect_t *pbox = sarea_priv->boxes;
14046393Scg149915 int i;
14056393Scg149915 RING_LOCALS;
14066393Scg149915
14076393Scg149915 /* Do some trivial performance monitoring... */
14086393Scg149915 if (dev_priv->do_boxes)
14096393Scg149915 radeon_cp_performance_boxes(dev_priv);
14106393Scg149915
14116393Scg149915 /*
14126393Scg149915 * Wait for the 3D stream to idle before dispatching the bitblt.
14136393Scg149915 * This will prevent data corruption between the two streams.
14146393Scg149915 */
14156393Scg149915 BEGIN_RING(2);
14166393Scg149915
14176393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
14186393Scg149915
14196393Scg149915 ADVANCE_RING();
14206393Scg149915
14216393Scg149915 for (i = 0; i < nbox; i++) {
14226393Scg149915 int x = pbox[i].x1;
14236393Scg149915 int y = pbox[i].y1;
14246393Scg149915 int w = pbox[i].x2 - x;
14256393Scg149915 int h = pbox[i].y2 - y;
14266393Scg149915
14276393Scg149915 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
14286393Scg149915
14296393Scg149915 BEGIN_RING(9);
14306393Scg149915
14316393Scg149915 OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
14326393Scg149915 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
14336393Scg149915 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
14346393Scg149915 RADEON_GMC_BRUSH_NONE |
14356393Scg149915 (dev_priv->color_fmt << 8) |
14366393Scg149915 RADEON_GMC_SRC_DATATYPE_COLOR |
14376393Scg149915 RADEON_ROP3_S |
14386393Scg149915 RADEON_DP_SRC_SOURCE_MEMORY |
14396393Scg149915 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
14406393Scg149915
14416393Scg149915 /* Make this work even if front & back are flipped: */
14426393Scg149915 OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
14436393Scg149915 if (dev_priv->current_page == 0) {
14446393Scg149915 OUT_RING(dev_priv->back_pitch_offset);
14456393Scg149915 OUT_RING(dev_priv->front_pitch_offset);
14466393Scg149915 } else {
14476393Scg149915 OUT_RING(dev_priv->front_pitch_offset);
14486393Scg149915 OUT_RING(dev_priv->back_pitch_offset);
14496393Scg149915 }
14506393Scg149915
14516393Scg149915 OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
14526393Scg149915 OUT_RING((x << 16) | y);
14536393Scg149915 OUT_RING((x << 16) | y);
14546393Scg149915 OUT_RING((w << 16) | h);
14556393Scg149915
14566393Scg149915 ADVANCE_RING();
14576393Scg149915 }
14586393Scg149915
14596393Scg149915 /*
14606393Scg149915 * Increment the frame counter. The client-side 3D driver must
14616393Scg149915 * throttle the framerate by waiting for this value before
14626393Scg149915 * performing the swapbuffer ioctl.
14636393Scg149915 */
14646393Scg149915 dev_priv->sarea_priv->last_frame ++;
14656393Scg149915
14666393Scg149915 BEGIN_RING(4);
14676393Scg149915
14686393Scg149915 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
14696393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
14706393Scg149915
14716393Scg149915 ADVANCE_RING();
14726393Scg149915 }
14736393Scg149915
radeon_cp_dispatch_flip(drm_device_t * dev)14746393Scg149915 static void radeon_cp_dispatch_flip(drm_device_t *dev)
14756393Scg149915 {
14766393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
14776393Scg149915 drm_sarea_t *sarea = (drm_sarea_t *)dev_priv->sarea->handle;
14786393Scg149915 int offset = (dev_priv->current_page == 1)
14796393Scg149915 ? dev_priv->front_offset : dev_priv->back_offset;
14806393Scg149915 RING_LOCALS;
14816393Scg149915 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
14826393Scg149915 __FUNCTION__,
14836393Scg149915 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
14846393Scg149915
14856393Scg149915 /* Do some trivial performance monitoring... */
14866393Scg149915 if (dev_priv->do_boxes) {
14876393Scg149915 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
14886393Scg149915 radeon_cp_performance_boxes(dev_priv);
14896393Scg149915 }
14906393Scg149915
14916393Scg149915 /* Update the frame offsets for both CRTCs */
14926393Scg149915 BEGIN_RING(6);
14936393Scg149915
14946393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
14956393Scg149915 OUT_RING_REG(RADEON_CRTC_OFFSET,
14966393Scg149915 ((sarea->frame.y * dev_priv->front_pitch +
14976393Scg149915 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) + offset);
14986393Scg149915 OUT_RING_REG(RADEON_CRTC2_OFFSET,
14996393Scg149915 dev_priv->sarea_priv->crtc2_base + offset);
15006393Scg149915
15016393Scg149915 ADVANCE_RING();
15026393Scg149915
15036393Scg149915 /*
15046393Scg149915 * Increment the frame counter. The client-side 3D driver must
15056393Scg149915 * throttle the framerate by waiting for this value before
15066393Scg149915 * performing the swapbuffer ioctl.
15076393Scg149915 */
15086393Scg149915 dev_priv->sarea_priv->last_frame ++;
15096393Scg149915 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
15106393Scg149915 1 - dev_priv->current_page;
15116393Scg149915
15126393Scg149915 BEGIN_RING(2);
15136393Scg149915
15146393Scg149915 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
15156393Scg149915
15166393Scg149915 ADVANCE_RING();
15176393Scg149915 }
15186393Scg149915
bad_prim_vertex_nr(int primitive,int nr)15196393Scg149915 static int bad_prim_vertex_nr(int primitive, int nr)
15206393Scg149915 {
15216393Scg149915 switch (primitive & RADEON_PRIM_TYPE_MASK) {
15226393Scg149915 case RADEON_PRIM_TYPE_NONE:
15236393Scg149915 case RADEON_PRIM_TYPE_POINT:
15246393Scg149915 return (nr < 1);
15256393Scg149915 case RADEON_PRIM_TYPE_LINE:
15266393Scg149915 return ((nr & 1) || nr == 0);
15276393Scg149915 case RADEON_PRIM_TYPE_LINE_STRIP:
15286393Scg149915 return (nr < 2);
15296393Scg149915 case RADEON_PRIM_TYPE_TRI_LIST:
15306393Scg149915 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
15316393Scg149915 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
15326393Scg149915 case RADEON_PRIM_TYPE_RECT_LIST:
15336393Scg149915 return (nr % 3 || nr == 0);
15346393Scg149915 case RADEON_PRIM_TYPE_TRI_FAN:
15356393Scg149915 case RADEON_PRIM_TYPE_TRI_STRIP:
15366393Scg149915 return (nr < 3);
15376393Scg149915 default:
15386393Scg149915 return (1);
15396393Scg149915 }
15406393Scg149915 }
15416393Scg149915
15426393Scg149915 typedef struct {
15436393Scg149915 unsigned int start;
15446393Scg149915 unsigned int finish;
15456393Scg149915 unsigned int prim;
15466393Scg149915 unsigned int numverts;
15476393Scg149915 unsigned int offset;
15486393Scg149915 unsigned int vc_format;
15496393Scg149915 } drm_radeon_tcl_prim_t;
15506393Scg149915
radeon_cp_dispatch_vertex(drm_device_t * dev,drm_buf_t * buf,drm_radeon_tcl_prim_t * prim)15516393Scg149915 static void radeon_cp_dispatch_vertex(drm_device_t *dev,
15526393Scg149915 drm_buf_t *buf, drm_radeon_tcl_prim_t *prim)
15536393Scg149915 {
15546393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
15556393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
15566393Scg149915 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
15576393Scg149915 int numverts = (int)prim->numverts;
15586393Scg149915 int nbox = sarea_priv->nbox;
15596393Scg149915 int i = 0;
15606393Scg149915 RING_LOCALS;
15616393Scg149915
15626393Scg149915 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
15636393Scg149915 prim->prim, prim->vc_format, prim->start,
15646393Scg149915 prim->finish, prim->numverts);
15656393Scg149915
15666393Scg149915 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
15676393Scg149915 DRM_ERROR("bad prim %x numverts %d\n",
15686393Scg149915 prim->prim, prim->numverts);
15696393Scg149915 return;
15706393Scg149915 }
15716393Scg149915
15726393Scg149915 do {
15736393Scg149915 /* Emit the next cliprect */
15746393Scg149915 if (i < nbox) {
15756393Scg149915 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
15766393Scg149915 }
15776393Scg149915
15786393Scg149915 /* Emit the vertex buffer rendering commands */
15796393Scg149915 BEGIN_RING(5);
15806393Scg149915
15816393Scg149915 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
15826393Scg149915 OUT_RING(offset);
15836393Scg149915 OUT_RING(numverts);
15846393Scg149915 OUT_RING(prim->vc_format);
15856393Scg149915 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
15866393Scg149915 RADEON_COLOR_ORDER_RGBA |
15876393Scg149915 RADEON_VTX_FMT_RADEON_MODE |
15886393Scg149915 (numverts << RADEON_NUM_VERTICES_SHIFT));
15896393Scg149915
15906393Scg149915 ADVANCE_RING();
15916393Scg149915
15926393Scg149915 i++;
15936393Scg149915 } while (i < nbox);
15946393Scg149915 }
15956393Scg149915
radeon_cp_discard_buffer(drm_device_t * dev,drm_buf_t * buf)15966393Scg149915 static void radeon_cp_discard_buffer(drm_device_t *dev, drm_buf_t *buf)
15976393Scg149915 {
15986393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
15996393Scg149915 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
16006393Scg149915 RING_LOCALS;
16016393Scg149915
16026393Scg149915 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
16036393Scg149915
16046393Scg149915 /* Emit the vertex buffer age */
16056393Scg149915 BEGIN_RING(2);
16066393Scg149915 RADEON_DISPATCH_AGE(buf_priv->age);
16076393Scg149915 ADVANCE_RING();
16086393Scg149915
16096393Scg149915 buf->pending = 1;
16106393Scg149915 buf->used = 0;
16116393Scg149915 }
16126393Scg149915
radeon_cp_dispatch_indirect(drm_device_t * dev,drm_buf_t * buf,int start,int end)16136393Scg149915 static void radeon_cp_dispatch_indirect(drm_device_t *dev,
16146393Scg149915 drm_buf_t *buf, int start, int end)
16156393Scg149915 {
16166393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
16176393Scg149915 RING_LOCALS;
16186393Scg149915 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
16196393Scg149915
16206393Scg149915 if (start != end) {
16216393Scg149915 int offset = (dev_priv->gart_buffers_offset +
16226393Scg149915 buf->offset + start);
16236393Scg149915 int dwords = (end - start + 3) / sizeof (u32);
16246393Scg149915
16256393Scg149915 /*
16266393Scg149915 * Indirect buffer data must be an even number of
16276393Scg149915 * dwords, so if we've been given an odd number we must
16286393Scg149915 * pad the data with a Type-2 CP packet.
16296393Scg149915 */
16306393Scg149915 if (dwords & 1) {
16316393Scg149915 u32 *data = (u32 *)(uintptr_t)
16326393Scg149915 ((char *)dev->agp_buffer_map->handle
16336393Scg149915 + buf->offset + start);
16346393Scg149915 data[dwords++] = RADEON_CP_PACKET2;
16356393Scg149915 }
16366393Scg149915
16376393Scg149915 /* Fire off the indirect buffer */
16386393Scg149915 BEGIN_RING(3);
16396393Scg149915
16406393Scg149915 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
16416393Scg149915 OUT_RING(offset);
16426393Scg149915 OUT_RING(dwords);
16436393Scg149915
16446393Scg149915 ADVANCE_RING();
16456393Scg149915 }
16466393Scg149915 }
16476393Scg149915
radeon_cp_dispatch_indices(drm_device_t * dev,drm_buf_t * elt_buf,drm_radeon_tcl_prim_t * prim)16486393Scg149915 static void radeon_cp_dispatch_indices(drm_device_t *dev,
16496393Scg149915 drm_buf_t *elt_buf, drm_radeon_tcl_prim_t *prim)
16506393Scg149915 {
16516393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
16526393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
16536393Scg149915 int offset = dev_priv->gart_buffers_offset + prim->offset;
16546393Scg149915 u32 *data;
16556393Scg149915 int dwords;
16566393Scg149915 int i = 0;
16576393Scg149915 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
16586393Scg149915 int count = (prim->finish - start) / sizeof (u16);
16596393Scg149915 int nbox = sarea_priv->nbox;
16606393Scg149915
16616393Scg149915 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
16626393Scg149915 prim->prim, prim->vc_format, prim->start,
16636393Scg149915 prim->finish, prim->offset, prim->numverts);
16646393Scg149915
16656393Scg149915 if (bad_prim_vertex_nr(prim->prim, count)) {
16666393Scg149915 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
16676393Scg149915 return;
16686393Scg149915 }
16696393Scg149915
16706393Scg149915 if (start >= prim->finish || (prim->start & 0x7)) {
16716393Scg149915 DRM_ERROR("buffer prim %d\n", prim->prim);
16726393Scg149915 return;
16736393Scg149915 }
16746393Scg149915
16756393Scg149915 dwords = (prim->finish - prim->start + 3) / sizeof (u32);
16766393Scg149915
16776393Scg149915 data = (u32 *)(uintptr_t)((char *)dev->agp_buffer_map->handle +
16786393Scg149915 elt_buf->offset + prim->start);
16796393Scg149915
16806393Scg149915 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
16816393Scg149915 data[1] = offset;
16826393Scg149915 data[2] = prim->numverts;
16836393Scg149915 data[3] = prim->vc_format;
16846393Scg149915 data[4] = (prim->prim |
16856393Scg149915 RADEON_PRIM_WALK_IND |
16866393Scg149915 RADEON_COLOR_ORDER_RGBA |
16876393Scg149915 RADEON_VTX_FMT_RADEON_MODE |
16886393Scg149915 (count << RADEON_NUM_VERTICES_SHIFT));
16896393Scg149915
16906393Scg149915 do {
16916393Scg149915 if (i < nbox)
16926393Scg149915 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
16936393Scg149915
16946393Scg149915 radeon_cp_dispatch_indirect(dev, elt_buf,
16956393Scg149915 prim->start, prim->finish);
16966393Scg149915
16976393Scg149915 i++;
16986393Scg149915 } while (i < nbox);
16996393Scg149915
17006393Scg149915 }
17016393Scg149915
17026393Scg149915 #define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
17036393Scg149915
17046393Scg149915 /*ARGSUSED*/
radeon_cp_dispatch_texture(drm_file_t * fpriv,drm_device_t * dev,drm_radeon_texture_t * tex,drm_radeon_tex_image_t * image,int mode)17056393Scg149915 static int radeon_cp_dispatch_texture(drm_file_t *fpriv,
17066393Scg149915 drm_device_t *dev, drm_radeon_texture_t *tex,
17076393Scg149915 drm_radeon_tex_image_t *image, int mode)
17086393Scg149915 {
17096393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
17106393Scg149915 drm_buf_t *buf;
17116393Scg149915 u32 format;
17126393Scg149915 u32 *buffer;
17136393Scg149915 const u8 __user *data;
17146393Scg149915 int size, dwords, tex_width, blit_width, spitch;
17156393Scg149915 u32 height;
17166393Scg149915 int i;
17176393Scg149915 u32 texpitch, microtile;
17186393Scg149915 u32 offset;
17196393Scg149915 RING_LOCALS;
17206393Scg149915
17216393Scg149915
17226393Scg149915 if (radeon_check_and_fixup_offset(dev_priv, fpriv, &tex->offset)) {
17236393Scg149915 DRM_ERROR("Invalid destination offset\n");
17246393Scg149915 return (EINVAL);
17256393Scg149915 }
17266393Scg149915
17276393Scg149915 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
17286393Scg149915
17296393Scg149915 /*
17306393Scg149915 * Flush the pixel cache. This ensures no pixel data gets mixed
17316393Scg149915 * up with the texture data from the host data blit, otherwise
17326393Scg149915 * part of the texture image may be corrupted.
17336393Scg149915 */
17346393Scg149915 BEGIN_RING(4);
17356393Scg149915 RADEON_FLUSH_CACHE();
17366393Scg149915 RADEON_WAIT_UNTIL_IDLE();
17376393Scg149915 ADVANCE_RING();
17386393Scg149915
17396393Scg149915 /*
17406393Scg149915 * The compiler won't optimize away a division by a variable,
17416393Scg149915 * even if the only legal values are powers of two. Thus, we'll
17426393Scg149915 * use a shift instead.
17436393Scg149915 */
17446393Scg149915 switch (tex->format) {
17456393Scg149915 case RADEON_TXFORMAT_ARGB8888:
17466393Scg149915 case RADEON_TXFORMAT_RGBA8888:
17476393Scg149915 format = RADEON_COLOR_FORMAT_ARGB8888;
17486393Scg149915 tex_width = tex->width * 4;
17496393Scg149915 blit_width = image->width * 4;
17506393Scg149915 break;
17516393Scg149915 case RADEON_TXFORMAT_AI88:
17526393Scg149915 case RADEON_TXFORMAT_ARGB1555:
17536393Scg149915 case RADEON_TXFORMAT_RGB565:
17546393Scg149915 case RADEON_TXFORMAT_ARGB4444:
17556393Scg149915 case RADEON_TXFORMAT_VYUY422:
17566393Scg149915 case RADEON_TXFORMAT_YVYU422:
17576393Scg149915 format = RADEON_COLOR_FORMAT_RGB565;
17586393Scg149915 tex_width = tex->width * 2;
17596393Scg149915 blit_width = image->width * 2;
17606393Scg149915 break;
17616393Scg149915 case RADEON_TXFORMAT_I8:
17626393Scg149915 case RADEON_TXFORMAT_RGB332:
17636393Scg149915 format = RADEON_COLOR_FORMAT_CI8;
17646393Scg149915 tex_width = tex->width * 1;
17656393Scg149915 blit_width = image->width * 1;
17666393Scg149915 break;
17676393Scg149915 default:
17686393Scg149915 DRM_ERROR("invalid texture format %d\n", tex->format);
17696393Scg149915 return (EINVAL);
17706393Scg149915 }
17716393Scg149915 spitch = blit_width >> 6;
17726393Scg149915 if (spitch == 0 && image->height > 1)
17736393Scg149915 return (EINVAL);
17746393Scg149915
17756393Scg149915 texpitch = tex->pitch;
17766393Scg149915 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
17776393Scg149915 microtile = 1;
17786393Scg149915 if (tex_width < 64) {
17796393Scg149915 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
17806393Scg149915 /* we got tiled coordinates, untile them */
17816393Scg149915 image->x *= 2;
17826393Scg149915 }
17836393Scg149915 } else
17846393Scg149915 microtile = 0;
17856393Scg149915
17866393Scg149915 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
17876393Scg149915
17886393Scg149915 do {
17896393Scg149915 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
17906393Scg149915 tex->offset >> 10, tex->pitch, tex->format,
17916393Scg149915 image->x, image->y, image->width, image->height);
17926393Scg149915
17936393Scg149915 /*
17946393Scg149915 * Make a copy of some parameters in case we have to
17956393Scg149915 * update them for a multi-pass texture blit.
17966393Scg149915 */
17976393Scg149915 height = image->height;
17986393Scg149915 data = (const u8 __user *)image->data;
17996393Scg149915
18006393Scg149915 size = height * blit_width;
18016393Scg149915
18026393Scg149915 if (size > RADEON_MAX_TEXTURE_SIZE) {
18036393Scg149915 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
18046393Scg149915 size = height * blit_width;
18056393Scg149915 } else if (size < 4 && size > 0) {
18066393Scg149915 size = 4;
18076393Scg149915 } else if (size == 0) {
18086393Scg149915 return (0);
18096393Scg149915 }
18106393Scg149915
18116393Scg149915 buf = radeon_freelist_get(dev);
18126393Scg149915 #if 0
18136393Scg149915 if (0 && !buf) {
18146393Scg149915 radeon_do_cp_idle(dev_priv);
18156393Scg149915 buf = radeon_freelist_get(dev);
18166393Scg149915 }
18176393Scg149915 #endif
18186393Scg149915 if (!buf) {
18196393Scg149915 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
18206393Scg149915
18216393Scg149915 #ifdef _MULTI_DATAMODEL
18226393Scg149915 if (ddi_model_convert_from(mode & FMODELS) ==
18236393Scg149915 DDI_MODEL_ILP32) {
18246393Scg149915 drm_radeon_tex_image_32_t image32;
18256393Scg149915 image32.x = image->x;
18266393Scg149915 image32.y = image->y;
18276393Scg149915 image32.width = image->width;
18286393Scg149915 image32.height = image->height;
18296393Scg149915 image32.data = (uint32_t)(uintptr_t)image->data;
18306393Scg149915 DRM_COPYTO_WITH_RETURN(tex->image, &image32,
18316393Scg149915 sizeof (image32));
18326393Scg149915 } else {
18336393Scg149915 #endif
18346393Scg149915 DRM_COPYTO_WITH_RETURN(tex->image, image,
18356393Scg149915 sizeof (*image));
18366393Scg149915 #ifdef _MULTI_DATAMODEL
18376393Scg149915 }
18386393Scg149915 #endif
18396393Scg149915 return (EAGAIN);
18406393Scg149915 }
18416393Scg149915
18426393Scg149915 /*
18436393Scg149915 * Dispatch the indirect buffer.
18446393Scg149915 */
18456393Scg149915 buffer = (u32 *)(uintptr_t)
18466393Scg149915 ((char *)dev->agp_buffer_map->handle + buf->offset);
18476393Scg149915
18486393Scg149915 dwords = size / 4;
18496393Scg149915
18506393Scg149915 #define RADEON_COPY_MT(_buf, _data, _width) \
18516393Scg149915 do { \
18526393Scg149915 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
18536393Scg149915 DRM_ERROR("%d: EFAULT on pad, %d bytes\n", \
18546393Scg149915 __LINE__, (_width)); \
18556393Scg149915 return (EFAULT); \
18566393Scg149915 } \
18576393Scg149915 } while (*"\0")
18586393Scg149915
18596393Scg149915 if (microtile) {
18606393Scg149915 /*
18616393Scg149915 * texture micro tiling in use, minimum texture
18626393Scg149915 * width is thus 16 bytes. however, we cannot use
18636393Scg149915 * blitter directly for texture width < 64 bytes,
18646393Scg149915 * since minimum tex pitch is 64 bytes and we need
18656393Scg149915 * this to match the texture width, otherwise the
18666393Scg149915 * blitter will tile it wrong. Thus, tiling manually
18676393Scg149915 * in this case. Additionally, need to special case
18686393Scg149915 * tex height = 1, since our actual image will have
18696393Scg149915 * height 2 and we need to ensure we don't read
18706393Scg149915 * beyond the texture size from user space.
18716393Scg149915 */
18726393Scg149915 if (tex->height == 1) {
18736393Scg149915 if (tex_width >= 64 || tex_width <= 16) {
18746393Scg149915 RADEON_COPY_MT(buffer, data,
18756393Scg149915 (int)(tex_width * sizeof (u32)));
18766393Scg149915 } else if (tex_width == 32) {
18776393Scg149915 RADEON_COPY_MT(buffer, data, 16);
18786393Scg149915 RADEON_COPY_MT(buffer + 8,
18796393Scg149915 data + 16, 16);
18806393Scg149915 }
18816393Scg149915 } else if (tex_width >= 64 || tex_width == 16) {
18826393Scg149915 RADEON_COPY_MT(buffer, data,
18836393Scg149915 (int)(dwords * sizeof (u32)));
18846393Scg149915 } else if (tex_width < 16) {
18856393Scg149915 for (i = 0; i < tex->height; i++) {
18866393Scg149915 RADEON_COPY_MT(buffer, data, tex_width);
18876393Scg149915 buffer += 4;
18886393Scg149915 data += tex_width;
18896393Scg149915 }
18906393Scg149915 } else if (tex_width == 32) {
18916393Scg149915 /*
18926393Scg149915 * TODO: make sure this works when not
18936393Scg149915 * fitting in one buffer
18946393Scg149915 * (i.e. 32bytes x 2048...)
18956393Scg149915 */
18966393Scg149915 for (i = 0; i < tex->height; i += 2) {
18976393Scg149915 RADEON_COPY_MT(buffer, data, 16);
18986393Scg149915 data += 16;
18996393Scg149915 RADEON_COPY_MT(buffer + 8, data, 16);
19006393Scg149915 data += 16;
19016393Scg149915 RADEON_COPY_MT(buffer + 4, data, 16);
19026393Scg149915 data += 16;
19036393Scg149915 RADEON_COPY_MT(buffer + 12, data, 16);
19046393Scg149915 data += 16;
19056393Scg149915 buffer += 16;
19066393Scg149915 }
19076393Scg149915 }
19086393Scg149915 } else {
19096393Scg149915 if (tex_width >= 32) {
19106393Scg149915 /*
19116393Scg149915 * Texture image width is larger than the
19126393Scg149915 * minimum, so we can upload it directly.
19136393Scg149915 */
19146393Scg149915 RADEON_COPY_MT(buffer, data,
19156393Scg149915 (int)(dwords * sizeof (u32)));
19166393Scg149915 } else {
19176393Scg149915 /*
19186393Scg149915 * Texture image width is less than the minimum,
19196393Scg149915 * so we need to pad out each image scanline to
19206393Scg149915 * the minimum width.
19216393Scg149915 */
19226393Scg149915 for (i = 0; i < tex->height; i++) {
19236393Scg149915 RADEON_COPY_MT(buffer, data, tex_width);
19246393Scg149915 buffer += 8;
19256393Scg149915 data += tex_width;
19266393Scg149915 }
19276393Scg149915 }
19286393Scg149915 }
19296393Scg149915
19306393Scg149915 #undef RADEON_COPY_MT
19316393Scg149915 buf->filp = fpriv;
19326393Scg149915 buf->used = size;
19336393Scg149915 offset = dev_priv->gart_buffers_offset + buf->offset;
19346393Scg149915
19356393Scg149915 BEGIN_RING(9);
19366393Scg149915 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
19376393Scg149915 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
19386393Scg149915 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
19396393Scg149915 RADEON_GMC_BRUSH_NONE |
19406393Scg149915 (format << 8) |
19416393Scg149915 RADEON_GMC_SRC_DATATYPE_COLOR |
19426393Scg149915 RADEON_ROP3_S |
19436393Scg149915 RADEON_DP_SRC_SOURCE_MEMORY |
19446393Scg149915 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
19456393Scg149915 OUT_RING((spitch << 22) | (offset >> 10));
19466393Scg149915 OUT_RING((texpitch << 22) | (tex->offset >> 10));
19476393Scg149915 OUT_RING(0);
19486393Scg149915 OUT_RING((image->x << 16) | image->y);
19496393Scg149915 OUT_RING((image->width << 16) | height);
19506393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
19516393Scg149915 ADVANCE_RING();
19526393Scg149915 COMMIT_RING();
19536393Scg149915
19546393Scg149915
19556393Scg149915 radeon_cp_discard_buffer(dev, buf);
19566393Scg149915
19576393Scg149915 /* Update the input parameters for next time */
19586393Scg149915 image->y += height;
19596393Scg149915 image->height -= height;
19606393Scg149915 image->data = (const u8 __user *)image->data + size;
19616393Scg149915 } while (image->height > 0);
19626393Scg149915
19636393Scg149915 /*
19646393Scg149915 * Flush the pixel cache after the blit completes. This ensures
19656393Scg149915 * the texture data is written out to memory before rendering
19666393Scg149915 * continues.
19676393Scg149915 */
19686393Scg149915 BEGIN_RING(4);
19696393Scg149915 RADEON_FLUSH_CACHE();
19706393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
19716393Scg149915 ADVANCE_RING();
19726393Scg149915 COMMIT_RING();
19736393Scg149915 return (0);
19746393Scg149915 }
19756393Scg149915
radeon_cp_dispatch_stipple(drm_device_t * dev,u32 * stipple)19766393Scg149915 static void radeon_cp_dispatch_stipple(drm_device_t *dev, u32 *stipple)
19776393Scg149915 {
19786393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
19796393Scg149915 int i;
19806393Scg149915 RING_LOCALS;
19816393Scg149915 DRM_DEBUG("\n");
19826393Scg149915
19836393Scg149915 BEGIN_RING(35);
19846393Scg149915
19856393Scg149915 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
19866393Scg149915 OUT_RING(0x00000000);
19876393Scg149915
19886393Scg149915 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
19896393Scg149915 for (i = 0; i < 32; i++) {
19906393Scg149915 OUT_RING(stipple[i]);
19916393Scg149915 }
19926393Scg149915
19936393Scg149915 ADVANCE_RING();
19946393Scg149915 }
19956393Scg149915
radeon_apply_surface_regs(int surf_index,drm_radeon_private_t * dev_priv)19966393Scg149915 static void radeon_apply_surface_regs(int surf_index,
19976393Scg149915 drm_radeon_private_t *dev_priv)
19986393Scg149915 {
19996393Scg149915 if (!dev_priv->mmio)
20006393Scg149915 return;
20016393Scg149915
20026393Scg149915 (void) radeon_do_cp_idle(dev_priv);
20036393Scg149915
20046393Scg149915 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
20056393Scg149915 dev_priv->surfaces[surf_index].flags);
20066393Scg149915 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
20076393Scg149915 dev_priv->surfaces[surf_index].lower);
20086393Scg149915 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
20096393Scg149915 dev_priv->surfaces[surf_index].upper);
20106393Scg149915 }
20116393Scg149915
20126393Scg149915 /*
20136393Scg149915 * Allocates a virtual surface
20146393Scg149915 * doesn't always allocate a real surface, will stretch an existing
20156393Scg149915 * surface when possible.
20166393Scg149915 *
20176393Scg149915 * Note that refcount can be at most 2, since during a free refcount=3
20186393Scg149915 * might mean we have to allocate a new surface which might not always
20196393Scg149915 * be available.
20206393Scg149915 * For example : we allocate three contigous surfaces ABC. If B is
20216393Scg149915 * freed, we suddenly need two surfaces to store A and C, which might
20226393Scg149915 * not always be available.
20236393Scg149915 */
alloc_surface(drm_radeon_surface_alloc_t * new,drm_radeon_private_t * dev_priv,drm_file_t * filp)20246393Scg149915 static int alloc_surface(drm_radeon_surface_alloc_t *new,
20256393Scg149915 drm_radeon_private_t *dev_priv, drm_file_t *filp)
20266393Scg149915 {
20276393Scg149915 struct radeon_virt_surface *s;
20286393Scg149915 int i;
20296393Scg149915 int virt_surface_index;
20306393Scg149915 uint32_t new_upper, new_lower;
20316393Scg149915
20326393Scg149915 new_lower = new->address;
20336393Scg149915 new_upper = new_lower + new->size - 1;
20346393Scg149915
20356393Scg149915 /* sanity check */
20366393Scg149915 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
20376393Scg149915 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
20386393Scg149915 RADEON_SURF_ADDRESS_FIXED_MASK) ||
20396393Scg149915 ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
20406393Scg149915 return (-1);
20416393Scg149915
20426393Scg149915 /* make sure there is no overlap with existing surfaces */
20436393Scg149915 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
20446393Scg149915 if ((dev_priv->surfaces[i].refcount != 0) &&
20456393Scg149915 (((new_lower >= dev_priv->surfaces[i].lower) &&
20466393Scg149915 (new_lower < dev_priv->surfaces[i].upper)) ||
20476393Scg149915 ((new_lower < dev_priv->surfaces[i].lower) &&
20486393Scg149915 (new_upper > dev_priv->surfaces[i].lower)))) {
20496393Scg149915 return (-1);
20506393Scg149915 }
20516393Scg149915 }
20526393Scg149915
20536393Scg149915 /* find a virtual surface */
20546393Scg149915 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
20556393Scg149915 if (dev_priv->virt_surfaces[i].filp == 0)
20566393Scg149915 break;
20576393Scg149915 if (i == 2 * RADEON_MAX_SURFACES) {
20586393Scg149915 return (-1);
20596393Scg149915 }
20606393Scg149915 virt_surface_index = i;
20616393Scg149915
20626393Scg149915 /* try to reuse an existing surface */
20636393Scg149915 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
20646393Scg149915 /* extend before */
20656393Scg149915 if ((dev_priv->surfaces[i].refcount == 1) &&
20666393Scg149915 (new->flags == dev_priv->surfaces[i].flags) &&
20676393Scg149915 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
20686393Scg149915 s = &(dev_priv->virt_surfaces[virt_surface_index]);
20696393Scg149915 s->surface_index = i;
20706393Scg149915 s->lower = new_lower;
20716393Scg149915 s->upper = new_upper;
20726393Scg149915 s->flags = new->flags;
20736393Scg149915 s->filp = filp;
20746393Scg149915 dev_priv->surfaces[i].refcount++;
20756393Scg149915 dev_priv->surfaces[i].lower = s->lower;
20766393Scg149915 radeon_apply_surface_regs(s->surface_index, dev_priv);
20776393Scg149915 return (virt_surface_index);
20786393Scg149915 }
20796393Scg149915
20806393Scg149915 /* extend after */
20816393Scg149915 if ((dev_priv->surfaces[i].refcount == 1) &&
20826393Scg149915 (new->flags == dev_priv->surfaces[i].flags) &&
20836393Scg149915 (new_lower == dev_priv->surfaces[i].upper + 1)) {
20846393Scg149915 s = &(dev_priv->virt_surfaces[virt_surface_index]);
20856393Scg149915 s->surface_index = i;
20866393Scg149915 s->lower = new_lower;
20876393Scg149915 s->upper = new_upper;
20886393Scg149915 s->flags = new->flags;
20896393Scg149915 s->filp = filp;
20906393Scg149915 dev_priv->surfaces[i].refcount++;
20916393Scg149915 dev_priv->surfaces[i].upper = s->upper;
20926393Scg149915 radeon_apply_surface_regs(s->surface_index, dev_priv);
20936393Scg149915 return (virt_surface_index);
20946393Scg149915 }
20956393Scg149915 }
20966393Scg149915
20976393Scg149915 /* okay, we need a new one */
20986393Scg149915 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
20996393Scg149915 if (dev_priv->surfaces[i].refcount == 0) {
21006393Scg149915 s = &(dev_priv->virt_surfaces[virt_surface_index]);
21016393Scg149915 s->surface_index = i;
21026393Scg149915 s->lower = new_lower;
21036393Scg149915 s->upper = new_upper;
21046393Scg149915 s->flags = new->flags;
21056393Scg149915 s->filp = filp;
21066393Scg149915 dev_priv->surfaces[i].refcount = 1;
21076393Scg149915 dev_priv->surfaces[i].lower = s->lower;
21086393Scg149915 dev_priv->surfaces[i].upper = s->upper;
21096393Scg149915 dev_priv->surfaces[i].flags = s->flags;
21106393Scg149915 radeon_apply_surface_regs(s->surface_index, dev_priv);
21116393Scg149915 return (virt_surface_index);
21126393Scg149915 }
21136393Scg149915 }
21146393Scg149915
21156393Scg149915 /* we didn't find anything */
21166393Scg149915 return (-1);
21176393Scg149915 }
21186393Scg149915
21196393Scg149915 static int
free_surface(drm_file_t * filp,drm_radeon_private_t * dev_priv,int lower)21206393Scg149915 free_surface(drm_file_t *filp, drm_radeon_private_t *dev_priv, int lower)
21216393Scg149915 {
21226393Scg149915 struct radeon_virt_surface *s;
21236393Scg149915 int i;
21246393Scg149915
21256393Scg149915 /* find the virtual surface */
21266393Scg149915 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
21276393Scg149915 s = &(dev_priv->virt_surfaces[i]);
21286393Scg149915 if (s->filp) {
21296393Scg149915 if ((lower == s->lower) && (filp == s->filp)) {
21306393Scg149915 if (dev_priv->surfaces[s->surface_index].
21316393Scg149915 lower == s->lower)
21326393Scg149915 dev_priv->surfaces[s->surface_index].
21336393Scg149915 lower = s->upper;
21346393Scg149915
21356393Scg149915 if (dev_priv->surfaces[s->surface_index].
21366393Scg149915 upper == s->upper)
21376393Scg149915 dev_priv->surfaces[s->surface_index].
21386393Scg149915 upper = s->lower;
21396393Scg149915
21406393Scg149915 dev_priv->surfaces[s->surface_index].refcount--;
21416393Scg149915 if (dev_priv->surfaces[s->surface_index].
21426393Scg149915 refcount == 0)
21436393Scg149915 dev_priv->surfaces[s->surface_index].
21446393Scg149915 flags = 0;
21456393Scg149915 s->filp = NULL;
21466393Scg149915 radeon_apply_surface_regs(s->surface_index,
21476393Scg149915 dev_priv);
21486393Scg149915 return (0);
21496393Scg149915 }
21506393Scg149915 }
21516393Scg149915 }
21526393Scg149915
21536393Scg149915 return (1);
21546393Scg149915 }
21556393Scg149915
radeon_surfaces_release(drm_file_t * filp,drm_radeon_private_t * dev_priv)21566393Scg149915 static void radeon_surfaces_release(drm_file_t *filp,
21576393Scg149915 drm_radeon_private_t *dev_priv)
21586393Scg149915 {
21596393Scg149915 int i;
21606393Scg149915
21616393Scg149915 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
21626393Scg149915 if (dev_priv->virt_surfaces[i].filp == filp)
21636393Scg149915 (void) free_surface(filp, dev_priv,
21646393Scg149915 dev_priv->virt_surfaces[i].lower);
21656393Scg149915 }
21666393Scg149915 }
21676393Scg149915
21686393Scg149915 /*
21696393Scg149915 * IOCTL functions
21706393Scg149915 */
21716393Scg149915 /*ARGSUSED*/
radeon_surface_alloc(DRM_IOCTL_ARGS)21726393Scg149915 static int radeon_surface_alloc(DRM_IOCTL_ARGS)
21736393Scg149915 {
21746393Scg149915 DRM_DEVICE;
21756393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
21766393Scg149915 drm_radeon_surface_alloc_t alloc;
21776393Scg149915
21786393Scg149915 if (!dev_priv) {
21796393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
21806393Scg149915 return (EINVAL);
21816393Scg149915 }
21826393Scg149915
21836393Scg149915 DRM_COPYFROM_WITH_RETURN(&alloc, (void *)data, sizeof (alloc));
21846393Scg149915
21856393Scg149915 if (alloc_surface(&alloc, dev_priv, fpriv) == -1)
21866393Scg149915 return (EINVAL);
21876393Scg149915 else
21886393Scg149915 return (0);
21896393Scg149915 }
21906393Scg149915
21916393Scg149915 /*ARGSUSED*/
radeon_surface_free(DRM_IOCTL_ARGS)21926393Scg149915 static int radeon_surface_free(DRM_IOCTL_ARGS)
21936393Scg149915 {
21946393Scg149915 DRM_DEVICE;
21956393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
21966393Scg149915 drm_radeon_surface_free_t memfree;
21976393Scg149915
21986393Scg149915 if (!dev_priv) {
21996393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
22006393Scg149915 return (EINVAL);
22016393Scg149915 }
22026393Scg149915
22036393Scg149915 DRM_COPYFROM_WITH_RETURN(&memfree, (void *)data, sizeof (memfree));
22046393Scg149915 if (free_surface(fpriv, dev_priv, memfree.address)) {
22056393Scg149915 return (EINVAL);
22066393Scg149915 }
22076393Scg149915 else
22086393Scg149915 return (0);
22096393Scg149915 }
22106393Scg149915
22116393Scg149915 /*ARGSUSED*/
radeon_cp_clear(DRM_IOCTL_ARGS)22126393Scg149915 static int radeon_cp_clear(DRM_IOCTL_ARGS)
22136393Scg149915 {
22146393Scg149915 DRM_DEVICE;
22156393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
22166393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
22176393Scg149915 drm_radeon_clear_t clear;
22186393Scg149915 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
22196393Scg149915
22206393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
22216393Scg149915
22226393Scg149915 #ifdef _MULTI_DATAMODEL
22236393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
22246393Scg149915 drm_radeon_clear_32_t clear32;
22256393Scg149915 DRM_COPYFROM_WITH_RETURN(&clear32, (void *)data,
22266393Scg149915 sizeof (clear32));
22276393Scg149915 clear.flags = clear32.flags;
22286393Scg149915 clear.clear_color = clear32.clear_color;
22296393Scg149915 clear.clear_depth = clear32.clear_depth;
22306393Scg149915 clear.color_mask = clear32.color_mask;
22316393Scg149915 clear.depth_mask = clear32.depth_mask;
22326393Scg149915 clear.depth_boxes = (void*)(uintptr_t)clear32.depth_boxes;
22336393Scg149915 } else {
22346393Scg149915 #endif
22356393Scg149915 DRM_COPYFROM_WITH_RETURN(&clear, (void *)data, sizeof (clear));
22366393Scg149915 #ifdef _MULTI_DATAMODEL
22376393Scg149915 }
22386393Scg149915 #endif
22396393Scg149915
22406393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
22416393Scg149915
22426393Scg149915 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
22436393Scg149915 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
22446393Scg149915
22456393Scg149915 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
22466393Scg149915 sarea_priv->nbox * sizeof (depth_boxes[0])))
22476393Scg149915 return (EFAULT);
22486393Scg149915
22496393Scg149915 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
22506393Scg149915
22516393Scg149915 COMMIT_RING();
22526393Scg149915 return (0);
22536393Scg149915 }
22546393Scg149915
22556393Scg149915 /*
22566393Scg149915 * Not sure why this isn't set all the time:
22576393Scg149915 */
radeon_do_init_pageflip(drm_device_t * dev)22586393Scg149915 static int radeon_do_init_pageflip(drm_device_t *dev)
22596393Scg149915 {
22606393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
22616393Scg149915 RING_LOCALS;
22626393Scg149915
22636393Scg149915 BEGIN_RING(6);
22646393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
22656393Scg149915 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
22666393Scg149915 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
22676393Scg149915 RADEON_CRTC_OFFSET_FLIP_CNTL);
22686393Scg149915 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
22696393Scg149915 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
22706393Scg149915 RADEON_CRTC_OFFSET_FLIP_CNTL);
22716393Scg149915 ADVANCE_RING();
22726393Scg149915
22736393Scg149915 dev_priv->page_flipping = 1;
22746393Scg149915 dev_priv->current_page = 0;
22756393Scg149915 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
22766393Scg149915
22776393Scg149915 return (0);
22786393Scg149915 }
22796393Scg149915
22806393Scg149915 /*
22816393Scg149915 * Called whenever a client dies, from drm_release.
22826393Scg149915 * NOTE: Lock isn't necessarily held when this is called!
22836393Scg149915 */
radeon_do_cleanup_pageflip(drm_device_t * dev)22846393Scg149915 static int radeon_do_cleanup_pageflip(drm_device_t *dev)
22856393Scg149915 {
22866393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
22876393Scg149915
22886393Scg149915 if (dev_priv->current_page != 0)
22896393Scg149915 radeon_cp_dispatch_flip(dev);
22906393Scg149915
22916393Scg149915 dev_priv->page_flipping = 0;
22926393Scg149915 return (0);
22936393Scg149915 }
22946393Scg149915
22956393Scg149915 /*
22966393Scg149915 * Swapping and flipping are different operations, need different ioctls.
22976393Scg149915 * They can & should be intermixed to support multiple 3d windows.
22986393Scg149915 */
22996393Scg149915 /*ARGSUSED*/
radeon_cp_flip(DRM_IOCTL_ARGS)23006393Scg149915 static int radeon_cp_flip(DRM_IOCTL_ARGS)
23016393Scg149915 {
23026393Scg149915 DRM_DEVICE;
23036393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
23046393Scg149915
23056393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
23066393Scg149915
23076393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
23086393Scg149915
23096393Scg149915 if (!dev_priv->page_flipping)
23106393Scg149915 (void) radeon_do_init_pageflip(dev);
23116393Scg149915
23126393Scg149915 radeon_cp_dispatch_flip(dev);
23136393Scg149915
23146393Scg149915 COMMIT_RING();
23156393Scg149915 return (0);
23166393Scg149915 }
23176393Scg149915
23186393Scg149915 /*ARGSUSED*/
radeon_cp_swap(DRM_IOCTL_ARGS)23196393Scg149915 static int radeon_cp_swap(DRM_IOCTL_ARGS)
23206393Scg149915 {
23216393Scg149915 DRM_DEVICE;
23226393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
23236393Scg149915 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
23246393Scg149915
23256393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
23266393Scg149915
23276393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
23286393Scg149915
23296393Scg149915 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
23306393Scg149915 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
23316393Scg149915
23326393Scg149915 radeon_cp_dispatch_swap(dev);
23336393Scg149915 dev_priv->sarea_priv->ctx_owner = 0;
23346393Scg149915
23356393Scg149915 COMMIT_RING();
23366393Scg149915 return (0);
23376393Scg149915 }
23386393Scg149915
23396393Scg149915 /*ARGSUSED*/
radeon_cp_vertex(DRM_IOCTL_ARGS)23406393Scg149915 static int radeon_cp_vertex(DRM_IOCTL_ARGS)
23416393Scg149915 {
23426393Scg149915 DRM_DEVICE;
23436393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
23446393Scg149915 drm_radeon_sarea_t *sarea_priv;
23456393Scg149915 drm_device_dma_t *dma = dev->dma;
23466393Scg149915 drm_buf_t *buf;
23476393Scg149915 drm_radeon_vertex_t vertex;
23486393Scg149915 drm_radeon_tcl_prim_t prim;
23496393Scg149915
23506393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
23516393Scg149915
23526393Scg149915 if (!dev_priv) {
23536393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
23546393Scg149915 return (EINVAL);
23556393Scg149915 }
23566393Scg149915
23576393Scg149915 sarea_priv = dev_priv->sarea_priv;
23586393Scg149915
23596393Scg149915 DRM_COPYFROM_WITH_RETURN(&vertex, (void *)data, sizeof (vertex));
23606393Scg149915
23616393Scg149915 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
23626393Scg149915 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
23636393Scg149915
23646393Scg149915 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
23656393Scg149915 DRM_ERROR("buffer index %d (of %d max)\n",
23666393Scg149915 vertex.idx, dma->buf_count - 1);
23676393Scg149915 return (EINVAL);
23686393Scg149915 }
23696393Scg149915 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
23706393Scg149915 DRM_ERROR("buffer prim %d\n", vertex.prim);
23716393Scg149915 return (EINVAL);
23726393Scg149915 }
23736393Scg149915
23746393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
23756393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
23766393Scg149915
23776393Scg149915 buf = dma->buflist[vertex.idx];
23786393Scg149915
23796393Scg149915 if (buf->filp != fpriv) {
23806393Scg149915 DRM_ERROR("process %d using buffer owned by %p\n",
23816393Scg149915 DRM_CURRENTPID, buf->filp);
23826393Scg149915 return (EINVAL);
23836393Scg149915 }
23846393Scg149915 if (buf->pending) {
23856393Scg149915 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
23866393Scg149915 return (EINVAL);
23876393Scg149915 }
23886393Scg149915
23896393Scg149915 /*
23906393Scg149915 * Build up a prim_t record:
23916393Scg149915 */
23926393Scg149915 if (vertex.count) {
23936393Scg149915 buf->used = vertex.count; /* not used? */
23946393Scg149915
23956393Scg149915 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
23966393Scg149915 if (radeon_emit_state(dev_priv, fpriv,
23976393Scg149915 &sarea_priv->context_state,
23986393Scg149915 sarea_priv->tex_state,
23996393Scg149915 sarea_priv->dirty)) {
24006393Scg149915 DRM_ERROR("radeon_emit_state failed\n");
24016393Scg149915 return (EINVAL);
24026393Scg149915 }
24036393Scg149915
24046393Scg149915 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
24056393Scg149915 RADEON_UPLOAD_TEX1IMAGES |
24066393Scg149915 RADEON_UPLOAD_TEX2IMAGES |
24076393Scg149915 RADEON_REQUIRE_QUIESCENCE);
24086393Scg149915 }
24096393Scg149915
24106393Scg149915 prim.start = 0;
24116393Scg149915 prim.finish = vertex.count; /* unused */
24126393Scg149915 prim.prim = vertex.prim;
24136393Scg149915 prim.numverts = vertex.count;
24146393Scg149915 prim.vc_format = dev_priv->sarea_priv->vc_format;
24156393Scg149915
24166393Scg149915 radeon_cp_dispatch_vertex(dev, buf, &prim);
24176393Scg149915 }
24186393Scg149915
24196393Scg149915 if (vertex.discard) {
24206393Scg149915 radeon_cp_discard_buffer(dev, buf);
24216393Scg149915 }
24226393Scg149915
24236393Scg149915 COMMIT_RING();
24246393Scg149915 return (0);
24256393Scg149915 }
24266393Scg149915
24276393Scg149915 /*ARGSUSED*/
radeon_cp_indices(DRM_IOCTL_ARGS)24286393Scg149915 static int radeon_cp_indices(DRM_IOCTL_ARGS)
24296393Scg149915 {
24306393Scg149915 DRM_DEVICE;
24316393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
24326393Scg149915 drm_radeon_sarea_t *sarea_priv;
24336393Scg149915 drm_device_dma_t *dma = dev->dma;
24346393Scg149915 drm_buf_t *buf;
24356393Scg149915 drm_radeon_indices_t elts;
24366393Scg149915 drm_radeon_tcl_prim_t prim;
24376393Scg149915 /* int count; */
24386393Scg149915
24396393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
24406393Scg149915
24416393Scg149915 if (!dev_priv) {
24426393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
24436393Scg149915 return (EINVAL);
24446393Scg149915 }
24456393Scg149915 sarea_priv = dev_priv->sarea_priv;
24466393Scg149915
24476393Scg149915 DRM_COPYFROM_WITH_RETURN(&elts, (void *)data, sizeof (elts));
24486393Scg149915
24496393Scg149915 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
24506393Scg149915 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
24516393Scg149915
24526393Scg149915 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
24536393Scg149915 DRM_ERROR("buffer index %d (of %d max)\n",
24546393Scg149915 elts.idx, dma->buf_count - 1);
24556393Scg149915 return (EINVAL);
24566393Scg149915 }
24576393Scg149915 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
24586393Scg149915 DRM_ERROR("buffer prim %d\n", elts.prim);
24596393Scg149915 return (EINVAL);
24606393Scg149915 }
24616393Scg149915
24626393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
24636393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
24646393Scg149915
24656393Scg149915 buf = dma->buflist[elts.idx];
24666393Scg149915
24676393Scg149915 if (buf->filp != fpriv) {
24686393Scg149915 DRM_ERROR("process %d using buffer owned by %p\n",
24696393Scg149915 DRM_CURRENTPID, buf->filp);
24706393Scg149915 return (EINVAL);
24716393Scg149915 }
24726393Scg149915 if (buf->pending) {
24736393Scg149915 DRM_ERROR("sending pending buffer %d\n", elts.idx);
24746393Scg149915 return (EINVAL);
24756393Scg149915 }
24766393Scg149915
24776393Scg149915 /* count = (elts.end - elts.start) / sizeof(u16); */
24786393Scg149915 elts.start -= RADEON_INDEX_PRIM_OFFSET;
24796393Scg149915
24806393Scg149915 if (elts.start & 0x7) {
24816393Scg149915 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
24826393Scg149915 return (EINVAL);
24836393Scg149915 }
24846393Scg149915 if (elts.start < buf->used) {
24856393Scg149915 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
24866393Scg149915 return (EINVAL);
24876393Scg149915 }
24886393Scg149915
24896393Scg149915 buf->used = elts.end;
24906393Scg149915
24916393Scg149915 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
24926393Scg149915 if (radeon_emit_state(dev_priv, fpriv,
24936393Scg149915 &sarea_priv->context_state,
24946393Scg149915 sarea_priv->tex_state,
24956393Scg149915 sarea_priv->dirty)) {
24966393Scg149915 DRM_ERROR("radeon_emit_state failed\n");
24976393Scg149915 return (EINVAL);
24986393Scg149915 }
24996393Scg149915
25006393Scg149915 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
25016393Scg149915 RADEON_UPLOAD_TEX1IMAGES |
25026393Scg149915 RADEON_UPLOAD_TEX2IMAGES |
25036393Scg149915 RADEON_REQUIRE_QUIESCENCE);
25046393Scg149915 }
25056393Scg149915
25066393Scg149915 /*
25076393Scg149915 * Build up a prim_t record:
25086393Scg149915 */
25096393Scg149915 prim.start = elts.start;
25106393Scg149915 prim.finish = elts.end;
25116393Scg149915 prim.prim = elts.prim;
25126393Scg149915 prim.offset = 0; /* offset from start of dma buffers */
25136393Scg149915 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
25146393Scg149915 prim.vc_format = dev_priv->sarea_priv->vc_format;
25156393Scg149915
25166393Scg149915 radeon_cp_dispatch_indices(dev, buf, &prim);
25176393Scg149915 if (elts.discard) {
25186393Scg149915 radeon_cp_discard_buffer(dev, buf);
25196393Scg149915 }
25206393Scg149915
25216393Scg149915 COMMIT_RING();
25226393Scg149915 return (0);
25236393Scg149915 }
25246393Scg149915
25256393Scg149915 /*ARGSUSED*/
radeon_cp_texture(DRM_IOCTL_ARGS)25266393Scg149915 static int radeon_cp_texture(DRM_IOCTL_ARGS)
25276393Scg149915 {
25286393Scg149915 DRM_DEVICE;
25296393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
25306393Scg149915 drm_radeon_texture_t tex;
25316393Scg149915 drm_radeon_tex_image_t image;
25326393Scg149915 int ret;
25336393Scg149915
25346393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
25356393Scg149915
25366393Scg149915 #ifdef _MULTI_DATAMODEL
25376393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
25386393Scg149915 drm_radeon_texture_32_t tex32;
25396393Scg149915 drm_radeon_tex_image_32_t image32;
25406393Scg149915
25416393Scg149915 DRM_COPYFROM_WITH_RETURN(&tex32, (void *)data, sizeof (tex32));
25426393Scg149915 if (tex32.image == 0) {
25436393Scg149915 DRM_ERROR("null texture image!\n");
25446393Scg149915 return (EINVAL);
25456393Scg149915 }
25466393Scg149915 if (DRM_COPY_FROM_USER(&image32,
25476393Scg149915 (void *)(uintptr_t)tex32.image, sizeof (image32))) {
25486393Scg149915 cmn_err(CE_WARN, "copyin32 failed");
25496393Scg149915 return (EFAULT);
25506393Scg149915 }
25516393Scg149915
25526393Scg149915 tex.offset = tex32.offset;
25536393Scg149915 tex.pitch = tex32.pitch;
25546393Scg149915 tex.format = tex32.format;
25556393Scg149915 tex.width = tex32.width;
25566393Scg149915 tex.height = tex32.height;
25576393Scg149915 tex.image = (void*)(uintptr_t)tex32.image;
25586393Scg149915
25596393Scg149915 image.x = image32.x;
25606393Scg149915 image.y = image32.y;
25616393Scg149915 image.width = image32.width;
25626393Scg149915 image.height = image32.height;
25636393Scg149915 image.data = (void*)(uintptr_t)image32.data;
25646393Scg149915
25656393Scg149915 } else {
25666393Scg149915 #endif
25676393Scg149915 DRM_COPYFROM_WITH_RETURN(&tex, (void *)data, sizeof (tex));
25686393Scg149915 if (tex.image == NULL) {
25696393Scg149915 return (EINVAL);
25706393Scg149915 }
25716393Scg149915 if (DRM_COPY_FROM_USER(&image,
25726393Scg149915 (drm_radeon_tex_image_t *)tex.image, sizeof (image))) {
25736393Scg149915 return (EFAULT);
25746393Scg149915 }
25756393Scg149915 #ifdef _MULTI_DATAMODEL
25766393Scg149915 }
25776393Scg149915 #endif
25786393Scg149915
25796393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
25806393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
25816393Scg149915
25826393Scg149915 ret = radeon_cp_dispatch_texture(fpriv, dev, &tex, &image, mode);
25836393Scg149915
25846393Scg149915 COMMIT_RING();
25856393Scg149915 return (ret);
25866393Scg149915 }
25876393Scg149915
25886393Scg149915 /*ARGSUSED*/
radeon_cp_stipple(DRM_IOCTL_ARGS)25896393Scg149915 static int radeon_cp_stipple(DRM_IOCTL_ARGS)
25906393Scg149915 {
25916393Scg149915 DRM_DEVICE;
25926393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
25936393Scg149915 drm_radeon_stipple_t stipple;
25946393Scg149915 u32 mask[32];
25956393Scg149915
25966393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
25976393Scg149915
25986393Scg149915 #ifdef _MULTI_DATAMODEL
25996393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
26006393Scg149915 drm_radeon_stipple_32_t stipple32;
26016393Scg149915 DRM_COPYFROM_WITH_RETURN(&stipple32, (void *)data,
26026393Scg149915 sizeof (stipple32));
26036393Scg149915 stipple.mask = (void *)(uintptr_t)stipple32.mask;
26046393Scg149915 } else {
26056393Scg149915 #endif
26066393Scg149915 DRM_COPYFROM_WITH_RETURN(&stipple, (void *)data,
26076393Scg149915 sizeof (stipple));
26086393Scg149915 #ifdef _MULTI_DATAMODEL
26096393Scg149915 }
26106393Scg149915 #endif
26116393Scg149915 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof (u32)))
26126393Scg149915 return (EFAULT);
26136393Scg149915
26146393Scg149915
26156393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
26166393Scg149915
26176393Scg149915 radeon_cp_dispatch_stipple(dev, mask);
26186393Scg149915
26196393Scg149915 COMMIT_RING();
26206393Scg149915 return (0);
26216393Scg149915 }
26226393Scg149915
26236393Scg149915 /*ARGSUSED*/
radeon_cp_indirect(DRM_IOCTL_ARGS)26246393Scg149915 static int radeon_cp_indirect(DRM_IOCTL_ARGS)
26256393Scg149915 {
26266393Scg149915 DRM_DEVICE;
26276393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
26286393Scg149915 drm_device_dma_t *dma = dev->dma;
26296393Scg149915 drm_buf_t *buf;
26306393Scg149915 drm_radeon_indirect_t indirect;
26316393Scg149915 RING_LOCALS;
26326393Scg149915
26336393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
26346393Scg149915
26356393Scg149915 if (!dev_priv) {
26366393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
26376393Scg149915 return (EINVAL);
26386393Scg149915 }
26396393Scg149915
26406393Scg149915 DRM_COPYFROM_WITH_RETURN(&indirect, (void *) data, sizeof (indirect));
26416393Scg149915
26426393Scg149915 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
26436393Scg149915 indirect.idx, indirect.start, indirect.end, indirect.discard);
26446393Scg149915
26456393Scg149915 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
26466393Scg149915 DRM_ERROR("buffer index %d (of %d max)\n",
26476393Scg149915 indirect.idx, dma->buf_count - 1);
26486393Scg149915 return (EINVAL);
26496393Scg149915 }
26506393Scg149915
26516393Scg149915 buf = dma->buflist[indirect.idx];
26526393Scg149915
26536393Scg149915 if (buf->filp != fpriv) {
26546393Scg149915 DRM_ERROR("process %d using buffer owned by %p\n",
26556393Scg149915 DRM_CURRENTPID, buf->filp);
26566393Scg149915 return (EINVAL);
26576393Scg149915 }
26586393Scg149915 if (buf->pending) {
26596393Scg149915 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
26606393Scg149915 return (EINVAL);
26616393Scg149915 }
26626393Scg149915
26636393Scg149915 if (indirect.start < buf->used) {
26646393Scg149915 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
26656393Scg149915 indirect.start, buf->used);
26666393Scg149915 return (EINVAL);
26676393Scg149915 }
26686393Scg149915
26696393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
26706393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
26716393Scg149915
26726393Scg149915 buf->used = indirect.end;
26736393Scg149915
26746393Scg149915 /*
26756393Scg149915 * Wait for the 3D stream to idle before the indirect buffer
26766393Scg149915 * containing 2D acceleration commands is processed.
26776393Scg149915 */
26786393Scg149915 BEGIN_RING(2);
26796393Scg149915
26806393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
26816393Scg149915
26826393Scg149915 ADVANCE_RING();
26836393Scg149915
26846393Scg149915 /*
26856393Scg149915 * Dispatch the indirect buffer full of commands from the
26866393Scg149915 * X server. This is insecure and is thus only available to
26876393Scg149915 * privileged clients.
26886393Scg149915 */
26896393Scg149915 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
26906393Scg149915 if (indirect.discard) {
26916393Scg149915 radeon_cp_discard_buffer(dev, buf);
26926393Scg149915 }
26936393Scg149915
26946393Scg149915 COMMIT_RING();
26956393Scg149915 return (0);
26966393Scg149915 }
26976393Scg149915
26986393Scg149915 /*ARGSUSED*/
radeon_cp_vertex2(DRM_IOCTL_ARGS)26996393Scg149915 static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
27006393Scg149915 {
27016393Scg149915 DRM_DEVICE;
27026393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
27036393Scg149915 drm_radeon_sarea_t *sarea_priv;
27046393Scg149915 drm_device_dma_t *dma = dev->dma;
27056393Scg149915 drm_buf_t *buf;
27066393Scg149915 drm_radeon_vertex2_t vertex;
27076393Scg149915 int i;
27086393Scg149915 unsigned char laststate;
27096393Scg149915
27106393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
27116393Scg149915
27126393Scg149915 if (!dev_priv) {
27136393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
27146393Scg149915 return (EINVAL);
27156393Scg149915 }
27166393Scg149915
27176393Scg149915 sarea_priv = dev_priv->sarea_priv;
27186393Scg149915
27196393Scg149915
27206393Scg149915 #ifdef _MULTI_DATAMODEL
27216393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
27226393Scg149915 drm_radeon_vertex2_32_t vertex32;
27236393Scg149915
27246393Scg149915 DRM_COPYFROM_WITH_RETURN(&vertex32, (void *) data,
27256393Scg149915 sizeof (vertex32));
27266393Scg149915 vertex.idx = vertex32.idx;
27276393Scg149915 vertex.discard = vertex32.discard;
27286393Scg149915 vertex.nr_states = vertex32.nr_states;
27296393Scg149915 vertex.state = (void *) (uintptr_t)vertex32.state;
27306393Scg149915 vertex.nr_prims = vertex32.nr_prims;
27316393Scg149915 vertex.prim = (void *)(uintptr_t)vertex32.prim;
27326393Scg149915 } else {
27336393Scg149915 #endif
27346393Scg149915 DRM_COPYFROM_WITH_RETURN(&vertex, (void *) data,
27356393Scg149915 sizeof (vertex));
27366393Scg149915 #ifdef _MULTI_DATAMODEL
27376393Scg149915 }
27386393Scg149915 #endif
27396393Scg149915
27406393Scg149915 DRM_DEBUG("pid=%d index=%d discard=%d\n",
27416393Scg149915 DRM_CURRENTPID, vertex.idx, vertex.discard);
27426393Scg149915
27436393Scg149915 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
27446393Scg149915 DRM_ERROR("buffer index %d (of %d max)\n",
27456393Scg149915 vertex.idx, dma->buf_count - 1);
27466393Scg149915 return (EINVAL);
27476393Scg149915 }
27486393Scg149915
27496393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
27506393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
27516393Scg149915
27526393Scg149915 buf = dma->buflist[vertex.idx];
27536393Scg149915
27546393Scg149915 if (buf->filp != fpriv) {
27556393Scg149915 DRM_ERROR("process %d using buffer owned by %p\n",
27566393Scg149915 DRM_CURRENTPID, buf->filp);
27576393Scg149915 return (EINVAL);
27586393Scg149915 }
27596393Scg149915
27606393Scg149915 if (buf->pending) {
27616393Scg149915 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
27626393Scg149915 return (EINVAL);
27636393Scg149915 }
27646393Scg149915
27656393Scg149915 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
27666393Scg149915 return (EINVAL);
27676393Scg149915
27686393Scg149915 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
27696393Scg149915 drm_radeon_prim_t prim;
27706393Scg149915 drm_radeon_tcl_prim_t tclprim;
27716393Scg149915
27726393Scg149915 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof (prim)))
27736393Scg149915 return (EFAULT);
27746393Scg149915
27756393Scg149915 if (prim.stateidx != laststate) {
27766393Scg149915 drm_radeon_state_t state;
27776393Scg149915
27786393Scg149915 if (DRM_COPY_FROM_USER(&state,
27796393Scg149915 &vertex.state[prim.stateidx], sizeof (state)))
27806393Scg149915 return (EFAULT);
27816393Scg149915
27826393Scg149915 if (radeon_emit_state2(dev_priv, fpriv, &state)) {
27836393Scg149915 DRM_ERROR("radeon_emit_state2 failed\n");
27846393Scg149915 return (EINVAL);
27856393Scg149915 }
27866393Scg149915
27876393Scg149915 laststate = prim.stateidx;
27886393Scg149915 }
27896393Scg149915
27906393Scg149915 tclprim.start = prim.start;
27916393Scg149915 tclprim.finish = prim.finish;
27926393Scg149915 tclprim.prim = prim.prim;
27936393Scg149915 tclprim.vc_format = prim.vc_format;
27946393Scg149915
27956393Scg149915 if (prim.prim & RADEON_PRIM_WALK_IND) {
27966393Scg149915 tclprim.offset = prim.numverts * 64;
27976393Scg149915 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
27986393Scg149915
27996393Scg149915 radeon_cp_dispatch_indices(dev, buf, &tclprim);
28006393Scg149915 } else {
28016393Scg149915 tclprim.numverts = prim.numverts;
28026393Scg149915 tclprim.offset = 0; /* not used */
28036393Scg149915
28046393Scg149915 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
28056393Scg149915 }
28066393Scg149915
28076393Scg149915 if (sarea_priv->nbox == 1)
28086393Scg149915 sarea_priv->nbox = 0;
28096393Scg149915 }
28106393Scg149915
28116393Scg149915 if (vertex.discard) {
28126393Scg149915 radeon_cp_discard_buffer(dev, buf);
28136393Scg149915 }
28146393Scg149915
28156393Scg149915 COMMIT_RING();
28166393Scg149915 return (0);
28176393Scg149915 }
28186393Scg149915
radeon_emit_packets(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)28196393Scg149915 static int radeon_emit_packets(drm_radeon_private_t *dev_priv,
28206393Scg149915 drm_file_t *filp_priv, drm_radeon_cmd_header_t header,
28216393Scg149915 drm_radeon_kcmd_buffer_t *cmdbuf)
28226393Scg149915 {
28236393Scg149915 int id = (int)header.packet.packet_id;
28246393Scg149915 int sz, reg;
28256393Scg149915 u32 *data = (u32 *)(uintptr_t)cmdbuf->buf;
28266393Scg149915 RING_LOCALS;
28276393Scg149915
28286393Scg149915 if (id >= RADEON_MAX_STATE_PACKETS)
28296393Scg149915 return (EINVAL);
28306393Scg149915
28316393Scg149915 sz = packet[id].len;
28326393Scg149915 reg = packet[id].start;
28336393Scg149915
28346393Scg149915 if (sz * sizeof (int) > cmdbuf->bufsz) {
28356393Scg149915 DRM_ERROR("Packet size provided larger than data provided\n");
28366393Scg149915 return (EINVAL);
28376393Scg149915 }
28386393Scg149915
28396393Scg149915 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
28406393Scg149915 DRM_ERROR("Packet verification failed\n");
28416393Scg149915 return (EINVAL);
28426393Scg149915 }
28436393Scg149915
28446393Scg149915 BEGIN_RING(sz + 1);
28456393Scg149915 OUT_RING(CP_PACKET0(reg, (sz - 1)));
28466393Scg149915 OUT_RING_TABLE(data, sz);
28476393Scg149915 ADVANCE_RING();
28486393Scg149915
28496393Scg149915 cmdbuf->buf += sz * sizeof (int);
28506393Scg149915 cmdbuf->bufsz -= sz * sizeof (int);
28516393Scg149915 return (0);
28526393Scg149915 }
28536393Scg149915
28546393Scg149915 static inline int
radeon_emit_scalars(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)28556393Scg149915 radeon_emit_scalars(drm_radeon_private_t *dev_priv,
28566393Scg149915 drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
28576393Scg149915 {
28586393Scg149915 int sz = header.scalars.count;
28596393Scg149915 int start = header.scalars.offset;
28606393Scg149915 int stride = header.scalars.stride;
28616393Scg149915 RING_LOCALS;
28626393Scg149915
28636393Scg149915 BEGIN_RING(3 + sz);
28646393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
28656393Scg149915 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
28666393Scg149915 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
28676393Scg149915 OUT_RING_TABLE(cmdbuf->buf, sz);
28686393Scg149915 ADVANCE_RING();
28696393Scg149915 cmdbuf->buf += sz * sizeof (int);
28706393Scg149915 cmdbuf->bufsz -= sz * sizeof (int);
28716393Scg149915 return (0);
28726393Scg149915 }
28736393Scg149915
28746393Scg149915 /*
28756393Scg149915 * God this is ugly
28766393Scg149915 */
28776393Scg149915 static inline int
radeon_emit_scalars2(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)28786393Scg149915 radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
28796393Scg149915 drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
28806393Scg149915 {
28816393Scg149915 int sz = header.scalars.count;
28826393Scg149915 int start = ((unsigned int)header.scalars.offset) + 0x100;
28836393Scg149915 int stride = header.scalars.stride;
28846393Scg149915 RING_LOCALS;
28856393Scg149915
28866393Scg149915 BEGIN_RING(3 + sz);
28876393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
28886393Scg149915 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
28896393Scg149915 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
28906393Scg149915 OUT_RING_TABLE(cmdbuf->buf, sz);
28916393Scg149915 ADVANCE_RING();
28926393Scg149915 cmdbuf->buf += sz * sizeof (int);
28936393Scg149915 cmdbuf->bufsz -= sz * sizeof (int);
28946393Scg149915 return (0);
28956393Scg149915 }
28966393Scg149915
28976393Scg149915 static inline int
radeon_emit_vectors(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)28986393Scg149915 radeon_emit_vectors(drm_radeon_private_t *dev_priv,
28996393Scg149915 drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
29006393Scg149915 {
29016393Scg149915 int sz = header.vectors.count;
29026393Scg149915 int start = header.vectors.offset;
29036393Scg149915 int stride = header.vectors.stride;
29046393Scg149915 RING_LOCALS;
29056393Scg149915
29066393Scg149915 BEGIN_RING(5 + sz);
29076393Scg149915 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
29086393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
29096393Scg149915 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
29106393Scg149915 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
29116393Scg149915 OUT_RING_TABLE(cmdbuf->buf, sz);
29126393Scg149915 ADVANCE_RING();
29136393Scg149915
29146393Scg149915 cmdbuf->buf += sz * sizeof (int);
29156393Scg149915 cmdbuf->bufsz -= sz * sizeof (int);
29166393Scg149915 return (0);
29176393Scg149915 }
29186393Scg149915
29196393Scg149915 static inline int
radeon_emit_veclinear(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)29206393Scg149915 radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
29216393Scg149915 drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
29226393Scg149915 {
29236393Scg149915 int sz = header.veclinear.count * 4;
29246393Scg149915 int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
29256393Scg149915 RING_LOCALS;
29266393Scg149915
29276393Scg149915 if (!sz)
29286393Scg149915 return (0);
29296393Scg149915 if (sz * 4 > cmdbuf->bufsz)
29306393Scg149915 return (EINVAL);
29316393Scg149915
29326393Scg149915 BEGIN_RING(5 + sz);
29336393Scg149915 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
29346393Scg149915 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
29356393Scg149915 OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
29366393Scg149915 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
29376393Scg149915 OUT_RING_TABLE(cmdbuf->buf, sz);
29386393Scg149915 ADVANCE_RING();
29396393Scg149915
29406393Scg149915 cmdbuf->buf += sz * sizeof (int);
29416393Scg149915 cmdbuf->bufsz -= sz * sizeof (int);
29426393Scg149915 return (0);
29436393Scg149915 }
29446393Scg149915
29456393Scg149915 static int
radeon_emit_packet3(drm_device_t * dev,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf)29466393Scg149915 radeon_emit_packet3(drm_device_t *dev, drm_file_t *filp_priv,
29476393Scg149915 drm_radeon_kcmd_buffer_t *cmdbuf)
29486393Scg149915 {
29496393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
29506393Scg149915 unsigned int cmdsz;
29516393Scg149915 int ret;
29526393Scg149915 RING_LOCALS;
29536393Scg149915
29546393Scg149915
29556393Scg149915 if ((ret = radeon_check_and_fixup_packet3(dev_priv,
29566393Scg149915 filp_priv, cmdbuf, &cmdsz))) {
29576393Scg149915 DRM_ERROR("Packet verification failed\n");
29586393Scg149915 return (ret);
29596393Scg149915 }
29606393Scg149915
29616393Scg149915 BEGIN_RING(cmdsz);
29626393Scg149915 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
29636393Scg149915 ADVANCE_RING();
29646393Scg149915
29656393Scg149915 cmdbuf->buf += cmdsz * 4;
29666393Scg149915 cmdbuf->bufsz -= cmdsz * 4;
29676393Scg149915 return (0);
29686393Scg149915 }
29696393Scg149915
radeon_emit_packet3_cliprect(drm_device_t * dev,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf,int orig_nbox)29706393Scg149915 static int radeon_emit_packet3_cliprect(drm_device_t *dev,
29716393Scg149915 drm_file_t *filp_priv,
29726393Scg149915 drm_radeon_kcmd_buffer_t *cmdbuf,
29736393Scg149915 int orig_nbox)
29746393Scg149915 {
29756393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
29766393Scg149915 drm_clip_rect_t box;
29776393Scg149915 unsigned int cmdsz;
29786393Scg149915 int ret;
29796393Scg149915 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
29806393Scg149915 int i = 0;
29816393Scg149915 RING_LOCALS;
29826393Scg149915
29836393Scg149915 if ((ret = radeon_check_and_fixup_packet3(dev_priv,
29846393Scg149915 filp_priv, cmdbuf, &cmdsz))) {
29856393Scg149915 DRM_ERROR("Packet verification failed\n");
29866393Scg149915 return (ret);
29876393Scg149915 }
29886393Scg149915
29896393Scg149915 if (!orig_nbox)
29906393Scg149915 goto out;
29916393Scg149915
29926393Scg149915 do {
29936393Scg149915 if (i < cmdbuf->nbox) {
29946393Scg149915 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof (box)))
29956393Scg149915 return (EFAULT);
29966393Scg149915 /*
29976393Scg149915 * FIXME The second and subsequent times round
29986393Scg149915 * this loop, send a WAIT_UNTIL_3D_IDLE before
29996393Scg149915 * calling emit_clip_rect(). This fixes a
30006393Scg149915 * lockup on fast machines when sending
30016393Scg149915 * several cliprects with a cmdbuf, as when
30026393Scg149915 * waving a 2D window over a 3D
30036393Scg149915 * window. Something in the commands from user
30046393Scg149915 * space seems to hang the card when they're
30056393Scg149915 * sent several times in a row. That would be
30066393Scg149915 * the correct place to fix it but this works
30076393Scg149915 * around it until I can figure that out - Tim
30086393Scg149915 * Smith
30096393Scg149915 */
30106393Scg149915 if (i) {
30116393Scg149915 BEGIN_RING(2);
30126393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
30136393Scg149915 ADVANCE_RING();
30146393Scg149915 }
30156393Scg149915 radeon_emit_clip_rect(dev_priv, &box);
30166393Scg149915 }
30176393Scg149915
30186393Scg149915 BEGIN_RING(cmdsz);
30196393Scg149915 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
30206393Scg149915 ADVANCE_RING();
30216393Scg149915
30226393Scg149915 } while (++i < cmdbuf->nbox);
30236393Scg149915 if (cmdbuf->nbox == 1)
30246393Scg149915 cmdbuf->nbox = 0;
30256393Scg149915
30266393Scg149915 out:
30276393Scg149915 cmdbuf->buf += cmdsz * 4;
30286393Scg149915 cmdbuf->bufsz -= cmdsz * 4;
30296393Scg149915 return (0);
30306393Scg149915 }
30316393Scg149915
30326393Scg149915 static int
radeon_emit_wait(drm_device_t * dev,int flags)30336393Scg149915 radeon_emit_wait(drm_device_t *dev, int flags)
30346393Scg149915 {
30356393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
30366393Scg149915 RING_LOCALS;
30376393Scg149915
30386393Scg149915 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
30396393Scg149915 switch (flags) {
30406393Scg149915 case RADEON_WAIT_2D:
30416393Scg149915 BEGIN_RING(2);
30426393Scg149915 RADEON_WAIT_UNTIL_2D_IDLE();
30436393Scg149915 ADVANCE_RING();
30446393Scg149915 break;
30456393Scg149915 case RADEON_WAIT_3D:
30466393Scg149915 BEGIN_RING(2);
30476393Scg149915 RADEON_WAIT_UNTIL_3D_IDLE();
30486393Scg149915 ADVANCE_RING();
30496393Scg149915 break;
30506393Scg149915 case RADEON_WAIT_2D | RADEON_WAIT_3D:
30516393Scg149915 BEGIN_RING(2);
30526393Scg149915 RADEON_WAIT_UNTIL_IDLE();
30536393Scg149915 ADVANCE_RING();
30546393Scg149915 break;
30556393Scg149915 default:
30566393Scg149915 return (EINVAL);
30576393Scg149915 }
30586393Scg149915
30596393Scg149915 return (0);
30606393Scg149915 }
30616393Scg149915
30626393Scg149915 /*ARGSUSED*/
radeon_cp_cmdbuf(DRM_IOCTL_ARGS)30636393Scg149915 static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
30646393Scg149915 {
30656393Scg149915 DRM_DEVICE;
30666393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
30676393Scg149915 drm_device_dma_t *dma = dev->dma;
30686393Scg149915 drm_buf_t *buf = NULL;
30696393Scg149915 int idx;
30706393Scg149915 drm_radeon_kcmd_buffer_t cmdbuf;
30716393Scg149915 drm_radeon_cmd_header_t header;
30726393Scg149915 int orig_nbox, orig_bufsz;
30736393Scg149915 char *kbuf = NULL;
30746393Scg149915
30756393Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
30766393Scg149915
30776393Scg149915 if (!dev_priv) {
30786393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
30796393Scg149915 return (EINVAL);
30806393Scg149915 }
30816393Scg149915
30826393Scg149915 #ifdef _MULTI_DATAMODEL
30836393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
30846393Scg149915 drm_radeon_kcmd_buffer_32_t cmdbuf32;
30856393Scg149915
30866393Scg149915 DRM_COPYFROM_WITH_RETURN(&cmdbuf32, (void *)data,
30876393Scg149915 sizeof (cmdbuf32));
30886393Scg149915 cmdbuf.bufsz = cmdbuf32.bufsz;
30896393Scg149915 cmdbuf.buf = (void *)(uintptr_t)cmdbuf32.buf;
30906393Scg149915 cmdbuf.nbox = cmdbuf32.nbox;
30916393Scg149915 cmdbuf.boxes = (void *)(uintptr_t)cmdbuf32.boxes;
30926393Scg149915 } else {
30936393Scg149915 #endif
30946393Scg149915 DRM_COPYFROM_WITH_RETURN(&cmdbuf, (void *) data,
30956393Scg149915 sizeof (cmdbuf));
30966393Scg149915 #ifdef _MULTI_DATAMODEL
30976393Scg149915 }
30986393Scg149915 #endif
30996393Scg149915 RING_SPACE_TEST_WITH_RETURN(dev_priv);
31006393Scg149915 VB_AGE_TEST_WITH_RETURN(dev_priv);
31016393Scg149915
31026393Scg149915 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
31036393Scg149915 return (EINVAL);
31046393Scg149915 }
31056393Scg149915
31066393Scg149915 /*
31076393Scg149915 * Allocate an in-kernel area and copy in the cmdbuf. Do this
31086393Scg149915 * to avoid races between checking values and using those values
31096393Scg149915 * in other code, and simply to avoid a lot of function calls
31106393Scg149915 * to copy in data.
31116393Scg149915 */
31126393Scg149915 orig_bufsz = cmdbuf.bufsz;
31136393Scg149915 if (orig_bufsz != 0) {
31146393Scg149915 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
31156393Scg149915 if (kbuf == NULL)
31166393Scg149915 return (ENOMEM);
31176393Scg149915 if (DRM_COPY_FROM_USER(kbuf, (void *)cmdbuf.buf,
31186393Scg149915 cmdbuf.bufsz)) {
31196393Scg149915 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
31206393Scg149915 return (EFAULT);
31216393Scg149915 }
31226393Scg149915 cmdbuf.buf = kbuf;
31236393Scg149915 }
31246393Scg149915
31256393Scg149915 orig_nbox = cmdbuf.nbox;
31266393Scg149915
31276393Scg149915 if (dev_priv->microcode_version == UCODE_R300) {
31286393Scg149915 int temp;
31296393Scg149915 temp = r300_do_cp_cmdbuf(dev, fpriv, &cmdbuf);
31306393Scg149915
31316393Scg149915 if (orig_bufsz != 0)
31326393Scg149915 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
31336393Scg149915
31346393Scg149915 return (temp);
31356393Scg149915 }
31366393Scg149915
31376393Scg149915 /* microcode_version != r300 */
31386393Scg149915 while (cmdbuf.bufsz >= sizeof (header)) {
31396393Scg149915
31406393Scg149915 header.i = *(int *)(uintptr_t)cmdbuf.buf;
31416393Scg149915 cmdbuf.buf += sizeof (header);
31426393Scg149915 cmdbuf.bufsz -= sizeof (header);
31436393Scg149915
31446393Scg149915 switch (header.header.cmd_type) {
31456393Scg149915 case RADEON_CMD_PACKET:
31466393Scg149915 DRM_DEBUG("RADEON_CMD_PACKET\n");
31476393Scg149915 if (radeon_emit_packets
31486393Scg149915 (dev_priv, fpriv, header, &cmdbuf)) {
31496393Scg149915 DRM_ERROR("radeon_emit_packets failed\n");
31506393Scg149915 goto err;
31516393Scg149915 }
31526393Scg149915 break;
31536393Scg149915
31546393Scg149915 case RADEON_CMD_SCALARS:
31556393Scg149915 DRM_DEBUG("RADEON_CMD_SCALARS\n");
31566393Scg149915 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
31576393Scg149915 DRM_ERROR("radeon_emit_scalars failed\n");
31586393Scg149915 goto err;
31596393Scg149915 }
31606393Scg149915 break;
31616393Scg149915
31626393Scg149915 case RADEON_CMD_VECTORS:
31636393Scg149915 DRM_DEBUG("RADEON_CMD_VECTORS\n");
31646393Scg149915 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
31656393Scg149915 DRM_ERROR("radeon_emit_vectors failed\n");
31666393Scg149915 goto err;
31676393Scg149915 }
31686393Scg149915 break;
31696393Scg149915
31706393Scg149915 case RADEON_CMD_DMA_DISCARD:
31716393Scg149915 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
31726393Scg149915 idx = header.dma.buf_idx;
31736393Scg149915 if (idx < 0 || idx >= dma->buf_count) {
31746393Scg149915 DRM_ERROR("buffer index %d (of %d max)\n",
31756393Scg149915 idx, dma->buf_count - 1);
31766393Scg149915 goto err;
31776393Scg149915 }
31786393Scg149915
31796393Scg149915 buf = dma->buflist[idx];
31806393Scg149915 if (buf->filp != fpriv || buf->pending) {
31816393Scg149915 DRM_ERROR("bad buffer %p %p %d\n",
31826393Scg149915 buf->filp, fpriv, buf->pending);
31836393Scg149915 goto err;
31846393Scg149915 }
31856393Scg149915
31866393Scg149915 radeon_cp_discard_buffer(dev, buf);
31876393Scg149915 break;
31886393Scg149915
31896393Scg149915 case RADEON_CMD_PACKET3:
31906393Scg149915 DRM_DEBUG("RADEON_CMD_PACKET3\n");
31916393Scg149915 if (radeon_emit_packet3(dev, fpriv, &cmdbuf)) {
31926393Scg149915 DRM_ERROR("radeon_emit_packet3 failed\n");
31936393Scg149915 goto err;
31946393Scg149915 }
31956393Scg149915 break;
31966393Scg149915
31976393Scg149915 case RADEON_CMD_PACKET3_CLIP:
31986393Scg149915 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
31996393Scg149915 if (radeon_emit_packet3_cliprect
32006393Scg149915 (dev, fpriv, &cmdbuf, orig_nbox)) {
32016393Scg149915 DRM_ERROR("radeon_emit_packet3_clip failed\n");
32026393Scg149915 goto err;
32036393Scg149915 }
32046393Scg149915 break;
32056393Scg149915
32066393Scg149915 case RADEON_CMD_SCALARS2:
32076393Scg149915 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
32086393Scg149915 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
32096393Scg149915 DRM_ERROR("radeon_emit_scalars2 failed\n");
32106393Scg149915 goto err;
32116393Scg149915 }
32126393Scg149915 break;
32136393Scg149915
32146393Scg149915 case RADEON_CMD_WAIT:
32156393Scg149915 DRM_DEBUG("RADEON_CMD_WAIT\n");
32166393Scg149915 if (radeon_emit_wait(dev, header.wait.flags)) {
32176393Scg149915 DRM_ERROR("radeon_emit_wait failed\n");
32186393Scg149915 goto err;
32196393Scg149915 }
32206393Scg149915 break;
32216393Scg149915 case RADEON_CMD_VECLINEAR:
32226393Scg149915 DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
32236393Scg149915 if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
32246393Scg149915 DRM_ERROR("radeon_emit_veclinear failed\n");
32256393Scg149915 goto err;
32266393Scg149915 }
32276393Scg149915 break;
32286393Scg149915
32296393Scg149915 default:
32306393Scg149915 DRM_ERROR("bad cmd_type %d at %p\n",
32316393Scg149915 header.header.cmd_type,
32326393Scg149915 cmdbuf.buf - sizeof (header));
32336393Scg149915 goto err;
32346393Scg149915 }
32356393Scg149915 }
32366393Scg149915
32376393Scg149915 if (orig_bufsz != 0)
32386393Scg149915 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
32396393Scg149915
32406393Scg149915 COMMIT_RING();
32416393Scg149915 return (0);
32426393Scg149915
32436393Scg149915 err:
32446393Scg149915 if (orig_bufsz != 0)
32456393Scg149915 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
32466393Scg149915 return (EINVAL);
32476393Scg149915 }
32486393Scg149915
32496393Scg149915 /*ARGSUSED*/
radeon_cp_getparam(DRM_IOCTL_ARGS)32506393Scg149915 static int radeon_cp_getparam(DRM_IOCTL_ARGS)
32516393Scg149915 {
32526393Scg149915 DRM_DEVICE;
32536393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
32546393Scg149915 drm_radeon_getparam_t param;
32556393Scg149915 int value;
32566393Scg149915
32576393Scg149915 if (!dev_priv) {
32586393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
32596393Scg149915 return (EINVAL);
32606393Scg149915 }
32616393Scg149915
32626393Scg149915 #ifdef _MULTI_DATAMODEL
32636393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
32646393Scg149915 drm_radeon_getparam_32_t param32;
32656393Scg149915
32666393Scg149915 DRM_COPYFROM_WITH_RETURN(¶m32,
32676393Scg149915 (drm_radeon_getparam_32_t *)data, sizeof (param32));
32686393Scg149915 param.param = param32.param;
32696393Scg149915 param.value = (void *)(uintptr_t)param32.value;
32706393Scg149915 } else {
32716393Scg149915 #endif
32726393Scg149915 DRM_COPYFROM_WITH_RETURN(¶m,
32736393Scg149915 (drm_radeon_getparam_t *)data, sizeof (param));
32746393Scg149915 #ifdef _MULTI_DATAMODEL
32756393Scg149915 }
32766393Scg149915 #endif
32776393Scg149915 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
32786393Scg149915
32796393Scg149915 switch (param.param) {
32806393Scg149915 case RADEON_PARAM_GART_BUFFER_OFFSET:
32816393Scg149915 value = dev_priv->gart_buffers_offset;
32826393Scg149915 break;
32836393Scg149915 case RADEON_PARAM_LAST_FRAME:
32846393Scg149915 dev_priv->stats.last_frame_reads++;
32856393Scg149915 value = GET_SCRATCH(0);
32866393Scg149915 break;
32876393Scg149915 case RADEON_PARAM_LAST_DISPATCH:
32886393Scg149915 value = GET_SCRATCH(1);
32896393Scg149915 break;
32906393Scg149915 case RADEON_PARAM_LAST_CLEAR:
32916393Scg149915 dev_priv->stats.last_clear_reads++;
32926393Scg149915 value = GET_SCRATCH(2);
32936393Scg149915 break;
32946393Scg149915 case RADEON_PARAM_IRQ_NR:
32956393Scg149915 value = dev->irq;
32966393Scg149915 break;
32976393Scg149915 case RADEON_PARAM_GART_BASE:
32986393Scg149915 value = dev_priv->gart_vm_start;
32996393Scg149915 break;
33006393Scg149915 case RADEON_PARAM_REGISTER_HANDLE:
33016393Scg149915 value = dev_priv->mmio->offset;
33026393Scg149915 break;
33036393Scg149915 case RADEON_PARAM_STATUS_HANDLE:
33046393Scg149915 value = dev_priv->ring_rptr_offset;
33056393Scg149915 break;
33066393Scg149915 #ifndef __LP64__
33076393Scg149915 /*
33086393Scg149915 * This ioctl() doesn't work on 64-bit platforms because
33096393Scg149915 * hw_lock is a pointer which can't fit into an int-sized
33106393Scg149915 * variable. According to Michel Dänzer, the ioctl) is
33116393Scg149915 * only used on embedded platforms, so not supporting it
33126393Scg149915 * shouldn't be a problem. If the same functionality is
33136393Scg149915 * needed on 64-bit platforms, a new ioctl() would have
33146393Scg149915 * to be added, so backwards-compatibility for the embedded
33156393Scg149915 * platforms can be maintained. --davidm 4-Feb-2004.
33166393Scg149915 */
33176393Scg149915 case RADEON_PARAM_SAREA_HANDLE:
33186393Scg149915 /* The lock is the first dword in the sarea. */
33196393Scg149915 value = (long)dev->lock.hw_lock;
33206393Scg149915 break;
33216393Scg149915 #endif
33226393Scg149915 case RADEON_PARAM_GART_TEX_HANDLE:
33236393Scg149915 value = dev_priv->gart_textures_offset;
33246393Scg149915 break;
33256393Scg149915 case RADEON_PARAM_SCRATCH_OFFSET:
33266393Scg149915 if (!dev_priv->writeback_works)
33276393Scg149915 return (EINVAL);
33286393Scg149915 value = RADEON_SCRATCH_REG_OFFSET;
33296393Scg149915 break;
33306393Scg149915
33316393Scg149915 case RADEON_PARAM_CARD_TYPE:
33326393Scg149915 if (dev_priv->flags & RADEON_IS_PCIE)
33336393Scg149915 value = RADEON_CARD_PCIE;
33346393Scg149915 else if (dev_priv->flags & RADEON_IS_AGP)
33356393Scg149915 value = RADEON_CARD_AGP;
33366393Scg149915 else
33376393Scg149915 value = RADEON_CARD_PCI;
33386393Scg149915 break;
33396393Scg149915 case RADEON_PARAM_VBLANK_CRTC:
33406393Scg149915 value = radeon_vblank_crtc_get(dev);
33416393Scg149915 break;
33426393Scg149915 default:
33436393Scg149915 return (EINVAL);
33446393Scg149915 }
33456393Scg149915
33466393Scg149915 if (DRM_COPY_TO_USER(param.value, &value, sizeof (int))) {
33476393Scg149915 DRM_ERROR("copy_to_user\n");
33486393Scg149915 return (EFAULT);
33496393Scg149915 }
33506393Scg149915 return (0);
33516393Scg149915 }
33526393Scg149915
33536393Scg149915 /*ARGSUSED*/
radeon_cp_setparam(DRM_IOCTL_ARGS)33546393Scg149915 static int radeon_cp_setparam(DRM_IOCTL_ARGS)
33556393Scg149915 {
33566393Scg149915 DRM_DEVICE;
33576393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
33586393Scg149915 drm_radeon_setparam_t sp;
33596393Scg149915 struct drm_radeon_driver_file_fields *radeon_priv;
33606393Scg149915
33616393Scg149915 if (!dev_priv) {
33626393Scg149915 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
33636393Scg149915 return (EINVAL);
33646393Scg149915 }
33656393Scg149915
33666393Scg149915 #ifdef _MULTI_DATAMODEL
33676393Scg149915 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
33686393Scg149915 drm_radeon_setparam_32_t sp32;
33696393Scg149915
33706393Scg149915 DRM_COPYFROM_WITH_RETURN(&sp32, (void *) data, sizeof (sp32));
33716393Scg149915 sp.param = sp32.param;
33726393Scg149915 sp.value = sp32.value;
33736393Scg149915 } else {
33746393Scg149915 #endif
33756393Scg149915 DRM_COPYFROM_WITH_RETURN(&sp, (void *) data, sizeof (sp));
33766393Scg149915 #ifdef _MULTI_DATAMODEL
33776393Scg149915 }
33786393Scg149915 #endif
33796393Scg149915 switch (sp.param) {
33806393Scg149915 case RADEON_SETPARAM_FB_LOCATION:
33816393Scg149915 radeon_priv = fpriv->driver_priv;
33826393Scg149915 radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
33836393Scg149915 break;
33846393Scg149915 case RADEON_SETPARAM_SWITCH_TILING:
33856393Scg149915 if (sp.value == 0) {
33866393Scg149915 DRM_DEBUG("color tiling disabled\n");
33876393Scg149915 dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
33886393Scg149915 dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
33896393Scg149915 dev_priv->sarea_priv->tiling_enabled = 0;
33906393Scg149915 } else if (sp.value == 1) {
33916393Scg149915 DRM_DEBUG("color tiling enabled\n");
33926393Scg149915 dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
33936393Scg149915 dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
33946393Scg149915 dev_priv->sarea_priv->tiling_enabled = 1;
33956393Scg149915 }
33966393Scg149915 break;
33976393Scg149915 case RADEON_SETPARAM_PCIGART_LOCATION:
33986393Scg149915 dev_priv->pcigart_offset = (unsigned long)sp.value;
33996393Scg149915 break;
34006393Scg149915 case RADEON_SETPARAM_NEW_MEMMAP:
34016393Scg149915 dev_priv->new_memmap = (int)sp.value;
34026393Scg149915 break;
34036393Scg149915 case RADEON_SETPARAM_VBLANK_CRTC:
34046393Scg149915 return (radeon_vblank_crtc_set(dev, sp.value));
34056393Scg149915 default:
34066393Scg149915 DRM_DEBUG("Invalid parameter %d\n", sp.param);
34076393Scg149915 return (EINVAL);
34086393Scg149915 }
34096393Scg149915
34106393Scg149915 return (0);
34116393Scg149915 }
34126393Scg149915
34136393Scg149915 /*
34146393Scg149915 * When a client dies:
34156393Scg149915 * - Check for and clean up flipped page state
34166393Scg149915 * - Free any alloced GART memory.
34176393Scg149915 * - Free any alloced radeon surfaces.
34186393Scg149915 *
34196393Scg149915 * DRM infrastructure takes care of reclaiming dma buffers.
34206393Scg149915 */
34216393Scg149915 void
radeon_driver_preclose(drm_device_t * dev,drm_file_t * filp)34226393Scg149915 radeon_driver_preclose(drm_device_t *dev, drm_file_t *filp)
34236393Scg149915 {
34246393Scg149915 if (dev->dev_private) {
34256393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
34266393Scg149915 if (dev_priv->page_flipping) {
34276393Scg149915 (void) radeon_do_cleanup_pageflip(dev);
34286393Scg149915 }
34296393Scg149915 radeon_mem_release(filp, dev_priv->gart_heap);
34306393Scg149915 radeon_mem_release(filp, dev_priv->fb_heap);
34316393Scg149915 radeon_surfaces_release(filp, dev_priv);
34326393Scg149915 }
34336393Scg149915 }
34346393Scg149915
34356393Scg149915 void
radeon_driver_lastclose(drm_device_t * dev)34366393Scg149915 radeon_driver_lastclose(drm_device_t *dev)
34376393Scg149915 {
34386393Scg149915 radeon_do_release(dev);
34396393Scg149915 }
34406393Scg149915
34416393Scg149915 int
radeon_driver_open(drm_device_t * dev,drm_file_t * filp_priv)34426393Scg149915 radeon_driver_open(drm_device_t *dev, drm_file_t *filp_priv)
34436393Scg149915 {
34446393Scg149915 drm_radeon_private_t *dev_priv = dev->dev_private;
34456393Scg149915 struct drm_radeon_driver_file_fields *radeon_priv;
34466393Scg149915
34476393Scg149915 radeon_priv =
34486393Scg149915 (struct drm_radeon_driver_file_fields *)
34496393Scg149915 drm_alloc(sizeof (*radeon_priv), DRM_MEM_FILES);
34506393Scg149915
34516393Scg149915 if (!radeon_priv)
34526393Scg149915 return (-ENOMEM);
34536393Scg149915
34546393Scg149915 filp_priv->driver_priv = radeon_priv;
34556393Scg149915
34566393Scg149915 if (dev_priv)
34576393Scg149915 radeon_priv->radeon_fb_delta = dev_priv->fb_location;
34586393Scg149915 else
34596393Scg149915 radeon_priv->radeon_fb_delta = 0;
34606393Scg149915 return (0);
34616393Scg149915 }
34626393Scg149915
34636393Scg149915 /*ARGSUSED*/
34646393Scg149915 void
radeon_driver_postclose(drm_device_t * dev,drm_file_t * filp_priv)34656393Scg149915 radeon_driver_postclose(drm_device_t *dev, drm_file_t *filp_priv)
34666393Scg149915 {
34676393Scg149915 struct drm_radeon_driver_file_fields *radeon_priv =
34686393Scg149915 filp_priv->driver_priv;
34696393Scg149915
34706393Scg149915 drm_free(radeon_priv, sizeof (* radeon_priv), DRM_MEM_FILES);
34716393Scg149915 }
34726393Scg149915
34736393Scg149915 drm_ioctl_desc_t radeon_ioctls[] = {
34746393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] =
34756393Scg149915 {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
34766393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_START)] =
34776393Scg149915 {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
34786393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] =
34796393Scg149915 {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
34806393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] =
34816393Scg149915 {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
34826393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] =
34836393Scg149915 {radeon_cp_idle, DRM_AUTH},
34846393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] =
34856393Scg149915 {radeon_cp_resume, DRM_AUTH},
34866393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_RESET)] =
34876393Scg149915 {radeon_engine_reset, DRM_AUTH},
34886393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] =
34896393Scg149915 {radeon_fullscreen, DRM_AUTH},
34906393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_SWAP)] =
34916393Scg149915 {radeon_cp_swap, DRM_AUTH},
34926393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] =
34936393Scg149915 {radeon_cp_clear, DRM_AUTH},
34946393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] =
34956393Scg149915 {radeon_cp_vertex, DRM_AUTH},
34966393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_INDICES)] =
34976393Scg149915 {radeon_cp_indices, DRM_AUTH},
34986393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] =
34996393Scg149915 {radeon_cp_texture, DRM_AUTH},
35006393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] =
35016393Scg149915 {radeon_cp_stipple, DRM_AUTH},
35026393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] =
35036393Scg149915 {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
35046393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] =
35056393Scg149915 {radeon_cp_vertex2, DRM_AUTH},
35066393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] =
35076393Scg149915 {radeon_cp_cmdbuf, DRM_AUTH},
35086393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] =
35096393Scg149915 {radeon_cp_getparam, DRM_AUTH},
35106393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_FLIP)] =
35116393Scg149915 {radeon_cp_flip, DRM_AUTH},
35126393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] =
35136393Scg149915 {radeon_mem_alloc, DRM_AUTH},
35146393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_FREE)] =
35156393Scg149915 {radeon_mem_free, DRM_AUTH},
35166393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] =
35176393Scg149915 {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
35186393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] =
35196393Scg149915 {radeon_irq_emit, DRM_AUTH},
35206393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] =
35216393Scg149915 {radeon_irq_wait, DRM_AUTH},
35226393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] =
35236393Scg149915 {radeon_cp_setparam, DRM_AUTH},
35246393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] =
35256393Scg149915 {radeon_surface_alloc, DRM_AUTH},
35266393Scg149915 [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] =
35276393Scg149915 {radeon_surface_free, DRM_AUTH}
35286393Scg149915 };
35296393Scg149915
35306393Scg149915 int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
3531