Commit 82b6c3af authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm: ioremap balanced with iounmap for drivers/char/drm
  drm: fix error returns, sysfs error handling
  fix return code in error case.
  drm: mga: set dev_priv_size
  drm: savage: dev->agp_buffer_map is not initialized for AGP DMA on savages
  drm: radeon: only allow specific type-3 packetss through verifier
parents 9f4c7ac2 85abb3f9
...@@ -237,6 +237,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, ...@@ -237,6 +237,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) { if (!list) {
if (map->type == _DRM_REGISTERS)
drm_ioremapfree(map->handle, map->size, dev);
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL; return -EINVAL;
} }
...@@ -252,6 +254,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, ...@@ -252,6 +254,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
map->offset; map->offset;
ret = drm_map_handle(dev, &list->hash, user_token, 0); ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) { if (ret) {
if (map->type == _DRM_REGISTERS)
drm_ioremapfree(map->handle, map->size, dev);
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -42,13 +42,24 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL); ...@@ -42,13 +42,24 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
struct class *drm_sysfs_create(struct module *owner, char *name) struct class *drm_sysfs_create(struct module *owner, char *name)
{ {
struct class *class; struct class *class;
int err;
class = class_create(owner, name); class = class_create(owner, name);
if (!class) if (!class) {
return class; err = -ENOMEM;
goto err_out;
}
err = class_create_file(class, &class_attr_version);
if (err)
goto err_out_class;
class_create_file(class, &class_attr_version);
return class; return class;
err_out_class:
class_destroy(class);
err_out:
return ERR_PTR(err);
} }
/** /**
...@@ -96,20 +107,36 @@ static struct class_device_attribute class_device_attrs[] = { ...@@ -96,20 +107,36 @@ static struct class_device_attribute class_device_attrs[] = {
struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head) struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
{ {
struct class_device *class_dev; struct class_device *class_dev;
int i; int i, j, err;
class_dev = class_device_create(cs, NULL, class_dev = class_device_create(cs, NULL,
MKDEV(DRM_MAJOR, head->minor), MKDEV(DRM_MAJOR, head->minor),
&(head->dev->pdev)->dev, &(head->dev->pdev)->dev,
"card%d", head->minor); "card%d", head->minor);
if (!class_dev) if (!class_dev) {
return NULL; err = -ENOMEM;
goto err_out;
}
class_set_devdata(class_dev, head); class_set_devdata(class_dev, head);
for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
class_device_create_file(class_dev, &class_device_attrs[i]); err = class_device_create_file(class_dev,
&class_device_attrs[i]);
if (err)
goto err_out_files;
}
return class_dev; return class_dev;
err_out_files:
if (i > 0)
for (j = 0; j < i; j++)
class_device_remove_file(class_dev,
&class_device_attrs[i]);
class_device_unregister(class_dev);
err_out:
return ERR_PTR(err);
} }
/** /**
......
...@@ -47,6 +47,7 @@ static struct drm_driver driver = { ...@@ -47,6 +47,7 @@ static struct drm_driver driver = {
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
DRIVER_IRQ_VBL, DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load, .load = mga_driver_load,
.unload = mga_driver_unload, .unload = mga_driver_unload,
.lastclose = mga_driver_lastclose, .lastclose = mga_driver_lastclose,
......
...@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ...@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
return 0; return 0;
} }
static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
u32 *cmd = (u32 *) cmdbuf->buf;
int count, ret;
RING_LOCALS;
count=(cmd[0]>>16) & 0x3fff;
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return DRM_ERR(EINVAL);
}
ret = r300_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL);
}
BEGIN_RING(count+2);
OUT_RING(cmd[0]);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING();
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
return 0;
}
static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
...@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, ...@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
case RADEON_CNTL_BITBLT_MULTI: case RADEON_CNTL_BITBLT_MULTI:
return r300_emit_bitblt_multi(dev_priv, cmdbuf); return r300_emit_bitblt_multi(dev_priv, cmdbuf);
case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
return r300_emit_indx_buffer(dev_priv, cmdbuf);
case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
case RADEON_WAIT_FOR_IDLE: case RADEON_WAIT_FOR_IDLE:
case RADEON_CP_NOP: case RADEON_CP_NOP:
/* these packets are safe */ /* these packets are safe */
......
...@@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * ...@@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
unsigned int *cmdsz) unsigned int *cmdsz)
{ {
u32 *cmd = (u32 *) cmdbuf->buf; u32 *cmd = (u32 *) cmdbuf->buf;
u32 offset, narrays;
int count, i, k;
*cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
...@@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * ...@@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
} }
/* Check client state and fix it up if necessary */ switch(cmd[0] & 0xff00) {
if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ /* XXX Are there old drivers needing other packets? */
u32 offset;
case RADEON_3D_DRAW_IMMD:
case RADEON_3D_DRAW_VBUF:
case RADEON_3D_DRAW_INDX:
case RADEON_WAIT_FOR_IDLE:
case RADEON_CP_NOP:
case RADEON_3D_CLEAR_ZMASK:
/* case RADEON_CP_NEXT_CHAR:
case RADEON_CP_PLY_NEXTSCAN:
case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
/* these packets are safe */
break;
case RADEON_CP_3D_DRAW_IMMD_2:
case RADEON_CP_3D_DRAW_VBUF_2:
case RADEON_CP_3D_DRAW_INDX_2:
case RADEON_3D_CLEAR_HIZ:
/* safe but r200 only */
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
return DRM_ERR(EINVAL);
}
break;
case RADEON_3D_LOAD_VBPNTR:
count = (cmd[0] >> 16) & 0x3fff;
if (count > 18) { /* 12 arrays max */
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
return DRM_ERR(EINVAL);
}
/* carefully check packet contents */
narrays = cmd[1] & ~0xc000;
k = 0;
i = 2;
while ((k < narrays) && (i < (count + 2))) {
i++; /* skip attribute field */
if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
return DRM_ERR(EINVAL);
}
k++;
i++;
if (k == narrays)
break;
/* have one more to process, they come in pairs */
if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
return DRM_ERR(EINVAL);
}
k++;
i++;
}
/* do the counts match what we expect ? */
if ((k != narrays) || (i != (count + 2))) {
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
return DRM_ERR(EINVAL);
}
break;
case RADEON_3D_RNDR_GEN_INDX_PRIM:
if (dev_priv->microcode_version != UCODE_R100) {
DRM_ERROR("Invalid 3d packet for r200-class chip\n");
return DRM_ERR(EINVAL);
}
if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
DRM_ERROR("Invalid rndr_gen_indx offset\n");
return DRM_ERR(EINVAL);
}
break;
case RADEON_CP_INDX_BUFFER:
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
return DRM_ERR(EINVAL);
}
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return DRM_ERR(EINVAL);
}
if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL);
}
break;
case RADEON_CNTL_HOSTDATA_BLT:
case RADEON_CNTL_PAINT_MULTI:
case RADEON_CNTL_BITBLT_MULTI:
/* MSB of opcode: next DWORD GUI_CNTL */
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10; offset = cmd[2] << 10;
...@@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * ...@@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
} }
cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
} }
break;
default:
DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
return DRM_ERR(EINVAL);
} }
return 0; return 0;
......
...@@ -728,6 +728,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init) ...@@ -728,6 +728,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
dev_priv->status = NULL; dev_priv->status = NULL;
} }
if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, dev->agp_buffer_map = drm_core_findmap(dev,
init->buffers_offset); init->buffers_offset);
if (!dev->agp_buffer_map) { if (!dev->agp_buffer_map) {
......
...@@ -994,7 +994,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) ...@@ -994,7 +994,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
if (cmdbuf.size) { if (cmdbuf.size) {
kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
if (kcmd_addr == NULL) if (kcmd_addr == NULL)
return ENOMEM; return DRM_ERR(ENOMEM);
if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
cmdbuf.size * 8)) cmdbuf.size * 8))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment