Commit 7f1825da authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux

Pull drm fixes from Dave Airlie:
 "Nothing too astounding

   - nouveau: bunch of regression fixes and oops fixes
   - radeon: UMS fixes, rn50 fix, dma fix
   - udl: fix EDID retrieval for large EDIDs."

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
  udldrmfb: udl_get_edid: drop unneeded i--
  udldrmfb: udl_get_edid: usb_control_msg buffer must not be on the stack
  udldrmfb: Fix EDID not working with monitors with EDID extension blocks
  drm/nvc0/fb: fix crash when different mutex is used to protect same list
  drm/nouveau/clock: fix support for more than 2 monitors on nve0
  drm/nv50/disp: fix selection of bios script for analog outputs
  drm/nv17-50: restore fence buffer on resume
  drm/nouveau: fix blank LVDS screen regression on pre-nv50 cards
  drm/nouveau: fix nouveau_client allocation failure path
  drm/nouveau: don't return freed object from nouveau_handle_create
  drm/nouveau/vm: fix memory corruption when pgt allocation fails
  drm/nouveau: add locking around instobj list operations
  drm/nouveau: do not forcibly power on lvds panels
  drm/nouveau/devinit: ensure legacy vga control is enabled during post
  radeon/kms: fix dma relocation checking
  radeon/kms: force rn50 chip to always report connected on analog output
  drm/radeon: fix error path in kpage allocation
  drm/radeon: fix a bogus kfree
  drm/radeon: fix NULL pointer dereference in UMS mode
parents 6843cc0e 7b4cf994
...@@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg, ...@@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg,
ret = nouveau_handle_create(nv_object(client), ~0, ~0, ret = nouveau_handle_create(nv_object(client), ~0, ~0,
nv_object(client), &client->root); nv_object(client), &client->root);
if (ret) { if (ret)
nouveau_namedb_destroy(&client->base);
return ret; return ret;
}
/* prevent init/fini being called, os in in charge of this */ /* prevent init/fini being called, os in in charge of this */
atomic_set(&nv_object(client)->usecount, 2); atomic_set(&nv_object(client)->usecount, 2);
......
...@@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, ...@@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
namedb = namedb->parent; namedb = namedb->parent;
handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL); handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle) if (!handle)
return -ENOMEM; return -ENOMEM;
...@@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, ...@@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
} }
hprintk(handle, TRACE, "created\n"); hprintk(handle, TRACE, "created\n");
*phandle = handle;
return 0; return 0;
} }
......
...@@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) ...@@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
if (!(ctrl & (1 << head))) {
if (nv_device(priv)->chipset < 0x90 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0x92 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0xa0) {
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
i += 3; i += 4;
} else { } else {
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
ctrl = nv_rd32(priv, 0x610798 + (i * 8)); ctrl = nv_rd32(priv, 0x610798 + (i * 8));
i += 3; i += 4;
}
} }
if (!(ctrl & (1 << head))) if (!(ctrl & (1 << head)))
return false; return false;
i--;
data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
if (data) { if (data) {
...@@ -898,20 +901,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -898,20 +901,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
if (!(ctrl & (1 << head))) {
if (nv_device(priv)->chipset < 0x90 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0x92 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0xa0) {
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
i += 3; i += 4;
} else { } else {
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
ctrl = nv_rd32(priv, 0x610794 + (i * 8)); ctrl = nv_rd32(priv, 0x610794 + (i * 8));
i += 3; i += 4;
}
} }
if (!(ctrl & (1 << head))) if (!(ctrl & (1 << head)))
return 0x0000; return 0x0000;
i--;
data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
if (!data) if (!data)
......
...@@ -36,6 +36,9 @@ nouveau_client(void *obj) ...@@ -36,6 +36,9 @@ nouveau_client(void *obj)
int nouveau_client_create_(const char *name, u64 device, const char *cfg, int nouveau_client_create_(const char *name, u64 device, const char *cfg,
const char *dbg, int, void **); const char *dbg, int, void **);
#define nouveau_client_destroy(p) \
nouveau_namedb_destroy(&(p)->base)
int nouveau_client_init(struct nouveau_client *); int nouveau_client_init(struct nouveau_client *);
int nouveau_client_fini(struct nouveau_client *, bool suspend); int nouveau_client_fini(struct nouveau_client *, bool suspend);
......
...@@ -38,6 +38,8 @@ enum nvbios_pll_type { ...@@ -38,6 +38,8 @@ enum nvbios_pll_type {
PLL_UNK42 = 0x42, PLL_UNK42 = 0x42,
PLL_VPLL0 = 0x80, PLL_VPLL0 = 0x80,
PLL_VPLL1 = 0x81, PLL_VPLL1 = 0x81,
PLL_VPLL2 = 0x82,
PLL_VPLL3 = 0x83,
PLL_MAX = 0xff PLL_MAX = 0xff
}; };
......
...@@ -1534,7 +1534,6 @@ init_io(struct nvbios_init *init) ...@@ -1534,7 +1534,6 @@ init_io(struct nvbios_init *init)
mdelay(10); mdelay(10);
init_wr32(init, 0x614100, 0x10000018); init_wr32(init, 0x614100, 0x10000018);
init_wr32(init, 0x614900, 0x10000018); init_wr32(init, 0x614900, 0x10000018);
return;
} }
value = init_rdport(init, port) & mask; value = init_rdport(init, port) & mask;
......
...@@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) ...@@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
switch (info.type) { switch (info.type) {
case PLL_VPLL0: case PLL_VPLL0:
case PLL_VPLL1: case PLL_VPLL1:
case PLL_VPLL2:
case PLL_VPLL3:
nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
nv_wr32(priv, info.reg + 0x10, fN << 16); nv_wr32(priv, info.reg + 0x10, fN << 16);
......
...@@ -145,14 +145,14 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, ...@@ -145,14 +145,14 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
mem->memtype = type; mem->memtype = type;
mem->size = size; mem->size = size;
mutex_lock(&mm->mutex); mutex_lock(&pfb->base.mutex);
do { do {
if (back) if (back)
ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
else else
ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
if (ret) { if (ret) {
mutex_unlock(&mm->mutex); mutex_unlock(&pfb->base.mutex);
pfb->ram.put(pfb, &mem); pfb->ram.put(pfb, &mem);
return ret; return ret;
} }
...@@ -160,7 +160,7 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, ...@@ -160,7 +160,7 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
list_add_tail(&r->rl_entry, &mem->regions); list_add_tail(&r->rl_entry, &mem->regions);
size -= r->length; size -= r->length;
} while (size); } while (size);
mutex_unlock(&mm->mutex); mutex_unlock(&pfb->base.mutex);
r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
mem->offset = (u64)r->offset << 12; mem->offset = (u64)r->offset << 12;
......
...@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent, ...@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
mutex_lock(&imem->base.mutex);
list_add(&iobj->head, &imem->list); list_add(&iobj->head, &imem->list);
mutex_unlock(&imem->base.mutex);
return 0; return 0;
} }
void void
nouveau_instobj_destroy(struct nouveau_instobj *iobj) nouveau_instobj_destroy(struct nouveau_instobj *iobj)
{ {
if (iobj->head.prev) struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);
mutex_lock(&subdev->mutex);
list_del(&iobj->head); list_del(&iobj->head);
mutex_unlock(&subdev->mutex);
return nouveau_object_destroy(&iobj->base); return nouveau_object_destroy(&iobj->base);
} }
...@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) ...@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
if (ret) if (ret)
return ret; return ret;
mutex_lock(&imem->base.mutex);
list_for_each_entry(iobj, &imem->list, head) { list_for_each_entry(iobj, &imem->list, head) {
if (iobj->suspend) { if (iobj->suspend) {
for (i = 0; i < iobj->size; i += 4) for (i = 0; i < iobj->size; i += 4)
...@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) ...@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
} }
} }
mutex_unlock(&imem->base.mutex);
return 0; return 0;
} }
...@@ -104,17 +114,26 @@ int ...@@ -104,17 +114,26 @@ int
nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
{ {
struct nouveau_instobj *iobj; struct nouveau_instobj *iobj;
int i; int i, ret = 0;
if (suspend) { if (suspend) {
mutex_lock(&imem->base.mutex);
list_for_each_entry(iobj, &imem->list, head) { list_for_each_entry(iobj, &imem->list, head) {
iobj->suspend = vmalloc(iobj->size); iobj->suspend = vmalloc(iobj->size);
if (iobj->suspend) { if (!iobj->suspend) {
ret = -ENOMEM;
break;
}
for (i = 0; i < iobj->size; i += 4) for (i = 0; i < iobj->size; i += 4)
iobj->suspend[i / 4] = nv_ro32(iobj, i); iobj->suspend[i / 4] = nv_ro32(iobj, i);
} else
return -ENOMEM;
} }
mutex_unlock(&imem->base.mutex);
if (ret)
return ret;
} }
return nouveau_subdev_fini(&imem->base, suspend); return nouveau_subdev_fini(&imem->base, suspend);
......
...@@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, ...@@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
u64 mm_length = (offset + length) - mm_offset; u64 mm_length = (offset + length) - mm_offset;
int ret; int ret;
vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL); vm = kzalloc(sizeof(*vm), GFP_KERNEL);
if (!vm) if (!vm)
return -ENOMEM; return -ENOMEM;
...@@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, ...@@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
return ret; return ret;
} }
*pvm = vm;
return 0; return 0;
} }
......
...@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, ...@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
struct nouveau_encoder **pnv_encoder) struct nouveau_encoder **pnv_encoder)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct nouveau_i2c *i2c = nouveau_i2c(drm->device); struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
int i; struct nouveau_i2c_port *port = NULL;
int i, panel = -ENODEV;
/* eDP panels need powering on by us (if the VBIOS doesn't default it
* to on) before doing any AUX channel transactions. LVDS panel power
* is handled by the SOR itself, and not required for LVDS DDC.
*/
if (nv_connector->type == DCB_CONNECTOR_eDP) {
panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
if (panel == 0) {
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
msleep(300);
}
}
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
struct nouveau_i2c_port *port = NULL;
struct nouveau_encoder *nv_encoder; struct nouveau_encoder *nv_encoder;
struct drm_mode_object *obj; struct drm_mode_object *obj;
int id; int id;
...@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, ...@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
port = i2c->find(i2c, nv_encoder->dcb->i2c_index); port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
if (port && nv_probe_i2c(port, 0x50)) { if (port && nv_probe_i2c(port, 0x50)) {
*pnv_encoder = nv_encoder; *pnv_encoder = nv_encoder;
return port; break;
} }
port = NULL;
} }
return NULL; /* eDP panel not detected, restore panel power GPIO to previous
* state to avoid confusing the SOR for other output types.
*/
if (!port && panel == 0)
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
return port;
} }
static struct nouveau_encoder * static struct nouveau_encoder *
......
...@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev) ...@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
/* power on internal panel if it's not already. the init tables of
* some vbios default this to off for some reason, causing the
* panel to not work after resume
*/
if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) {
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
msleep(300);
}
/* enable polling for external displays */ /* enable polling for external displays */
drm_kms_helper_poll_enable(dev); drm_kms_helper_poll_enable(dev);
......
...@@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name, ...@@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name,
struct nouveau_cli *cli; struct nouveau_cli *cli;
int ret; int ret;
*pcli = NULL;
ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
nouveau_debug, size, pcli); nouveau_debug, size, pcli);
cli = *pcli; cli = *pcli;
if (ret) if (ret) {
if (cli)
nouveau_client_destroy(&cli->base);
*pcli = NULL;
return ret; return ret;
}
mutex_init(&cli->mutex); mutex_init(&cli->mutex);
return 0; return 0;
......
...@@ -60,6 +60,7 @@ u32 nv10_fence_read(struct nouveau_channel *); ...@@ -60,6 +60,7 @@ u32 nv10_fence_read(struct nouveau_channel *);
void nv10_fence_context_del(struct nouveau_channel *); void nv10_fence_context_del(struct nouveau_channel *);
void nv10_fence_destroy(struct nouveau_drm *); void nv10_fence_destroy(struct nouveau_drm *);
int nv10_fence_create(struct nouveau_drm *); int nv10_fence_create(struct nouveau_drm *);
void nv17_fence_resume(struct nouveau_drm *drm);
int nv50_fence_create(struct nouveau_drm *); int nv50_fence_create(struct nouveau_drm *);
int nv84_fence_create(struct nouveau_drm *); int nv84_fence_create(struct nouveau_drm *);
......
...@@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) ...@@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
static inline bool is_powersaving_dpms(int mode) static inline bool is_powersaving_dpms(int mode)
{ {
return (mode != DRM_MODE_DPMS_ON); return mode != DRM_MODE_DPMS_ON && mode != NV_DPMS_CLEARED;
} }
static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
......
...@@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm) ...@@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm)
kfree(priv); kfree(priv);
} }
void nv17_fence_resume(struct nouveau_drm *drm)
{
struct nv10_fence_priv *priv = drm->fence;
nouveau_bo_wr32(priv->bo, 0, priv->sequence);
}
int int
nv10_fence_create(struct nouveau_drm *drm) nv10_fence_create(struct nouveau_drm *drm)
{ {
...@@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm) ...@@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm)
if (ret == 0) { if (ret == 0) {
nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
priv->base.sync = nv17_fence_sync; priv->base.sync = nv17_fence_sync;
priv->base.resume = nv17_fence_resume;
} }
} }
......
...@@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm) ...@@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm)
if (ret == 0) { if (ret == 0) {
nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
priv->base.sync = nv17_fence_sync; priv->base.sync = nv17_fence_sync;
priv->base.resume = nv17_fence_resume;
} }
if (ret) if (ret)
......
...@@ -2476,9 +2476,11 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error) ...@@ -2476,9 +2476,11 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error)
kfree(parser->relocs); kfree(parser->relocs);
for (i = 0; i < parser->nchunks; i++) { for (i = 0; i < parser->nchunks; i++) {
kfree(parser->chunks[i].kdata); kfree(parser->chunks[i].kdata);
if (parser->rdev && (parser->rdev->flags & RADEON_IS_AGP)) {
kfree(parser->chunks[i].kpage[0]); kfree(parser->chunks[i].kpage[0]);
kfree(parser->chunks[i].kpage[1]); kfree(parser->chunks[i].kpage[1]);
} }
}
kfree(parser->chunks); kfree(parser->chunks);
kfree(parser->chunks_array); kfree(parser->chunks_array);
} }
...@@ -2561,16 +2563,16 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, ...@@ -2561,16 +2563,16 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_chunk *relocs_chunk; struct radeon_cs_chunk *relocs_chunk;
unsigned idx; unsigned idx;
*cs_reloc = NULL;
if (p->chunk_relocs_idx == -1) { if (p->chunk_relocs_idx == -1) {
DRM_ERROR("No relocation chunk !\n"); DRM_ERROR("No relocation chunk !\n");
return -EINVAL; return -EINVAL;
} }
*cs_reloc = NULL;
relocs_chunk = &p->chunks[p->chunk_relocs_idx]; relocs_chunk = &p->chunks[p->chunk_relocs_idx];
idx = p->dma_reloc_idx; idx = p->dma_reloc_idx;
if (idx >= relocs_chunk->length_dw) { if (idx >= p->nrelocs) {
DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
idx, relocs_chunk->length_dw); idx, p->nrelocs);
return -EINVAL; return -EINVAL;
} }
*cs_reloc = p->relocs_ptr[idx]; *cs_reloc = p->relocs_ptr[idx];
......
...@@ -279,13 +279,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) ...@@ -279,13 +279,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
p->chunks[p->chunk_ib_idx].length_dw); p->chunks[p->chunk_ib_idx].length_dw);
return -EINVAL; return -EINVAL;
} }
if ((p->rdev->flags & RADEON_IS_AGP)) { if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) {
p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { p->chunks[p->chunk_ib_idx].kpage[1] == NULL) {
kfree(p->chunks[i].kpage[0]); kfree(p->chunks[p->chunk_ib_idx].kpage[0]);
kfree(p->chunks[i].kpage[1]); kfree(p->chunks[p->chunk_ib_idx].kpage[1]);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -583,7 +583,8 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) ...@@ -583,7 +583,8 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
int i; int i;
int size = PAGE_SIZE; int size = PAGE_SIZE;
bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true; bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ?
false : true;
for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { for (i = ibc->last_copied_page + 1; i < pg_idx; i++) {
if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
......
...@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc ...@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
enum drm_connector_status found = connector_status_disconnected; enum drm_connector_status found = connector_status_disconnected;
bool color = true; bool color = true;
/* just don't bother on RN50 those chip are often connected to remoting
* console hw and often we get failure to load detect those. So to make
* everyone happy report the encoder as always connected.
*/
if (ASIC_IS_RN50(rdev)) {
return connector_status_connected;
}
/* save the regs we need */ /* save the regs we need */
vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
......
...@@ -22,13 +22,17 @@ ...@@ -22,13 +22,17 @@
static u8 *udl_get_edid(struct udl_device *udl) static u8 *udl_get_edid(struct udl_device *udl)
{ {
u8 *block; u8 *block;
char rbuf[3]; char *rbuf;
int ret, i; int ret, i;
block = kmalloc(EDID_LENGTH, GFP_KERNEL); block = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (block == NULL) if (block == NULL)
return NULL; return NULL;
rbuf = kmalloc(2, GFP_KERNEL);
if (rbuf == NULL)
goto error;
for (i = 0; i < EDID_LENGTH; i++) { for (i = 0; i < EDID_LENGTH; i++) {
ret = usb_control_msg(udl->ddev->usbdev, ret = usb_control_msg(udl->ddev->usbdev,
usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02),
...@@ -36,16 +40,17 @@ static u8 *udl_get_edid(struct udl_device *udl) ...@@ -36,16 +40,17 @@ static u8 *udl_get_edid(struct udl_device *udl)
HZ); HZ);
if (ret < 1) { if (ret < 1) {
DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
i--;
goto error; goto error;
} }
block[i] = rbuf[1]; block[i] = rbuf[1];
} }
kfree(rbuf);
return block; return block;
error: error:
kfree(block); kfree(block);
kfree(rbuf);
return NULL; return NULL;
} }
...@@ -57,6 +62,14 @@ static int udl_get_modes(struct drm_connector *connector) ...@@ -57,6 +62,14 @@ static int udl_get_modes(struct drm_connector *connector)
edid = (struct edid *)udl_get_edid(udl); edid = (struct edid *)udl_get_edid(udl);
/*
* We only read the main block, but if the monitor reports extension
* blocks then the drm edid code expects them to be present, so patch
* the extension count to 0.
*/
edid->checksum += edid->extensions;
edid->extensions = 0;
drm_mode_connector_update_edid_property(connector, edid); drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid); ret = drm_add_edid_modes(connector, edid);
kfree(edid); kfree(edid);
......
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