Commit 94bc70a8 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-nouveau-fixes' of...

Merge branch 'drm-nouveau-fixes' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

Regression fixes since rework mostly.

* 'drm-nouveau-fixes' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  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
parents 82ba789f 43f78979
...@@ -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 (nv_device(priv)->chipset < 0x90 || if (!(ctrl & (1 << head))) {
nv_device(priv)->chipset == 0x92 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0x92 ||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) nv_device(priv)->chipset == 0xa0) {
ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
i += 3; ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
} else { i += 4;
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) } else {
ctrl = nv_rd32(priv, 0x610798 + (i * 8)); for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
i += 3; ctrl = nv_rd32(priv, 0x610798 + (i * 8));
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 (nv_device(priv)->chipset < 0x90 || if (!(ctrl & (1 << head))) {
nv_device(priv)->chipset == 0x92 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0x92 ||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) nv_device(priv)->chipset == 0xa0) {
ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
i += 3; ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
} else { i += 4;
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) } else {
ctrl = nv_rd32(priv, 0x610794 + (i * 8)); for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
i += 3; ctrl = nv_rd32(priv, 0x610794 + (i * 8));
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);
list_del(&iobj->head);
mutex_lock(&subdev->mutex);
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) {
for (i = 0; i < iobj->size; i += 4) ret = -ENOMEM;
iobj->suspend[i / 4] = nv_ro32(iobj, i); break;
} else }
return -ENOMEM;
for (i = 0; i < iobj->size; i += 4)
iobj->suspend[i / 4] = nv_ro32(iobj, i);
} }
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)
......
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