mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-02 17:36:43 +07:00
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
This commit is contained in:
commit
94bc70a8e7
@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg,
|
||||
|
||||
ret = nouveau_handle_create(nv_object(client), ~0, ~0,
|
||||
nv_object(client), &client->root);
|
||||
if (ret) {
|
||||
nouveau_namedb_destroy(&client->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* prevent init/fini being called, os in in charge of this */
|
||||
atomic_set(&nv_object(client)->usecount, 2);
|
||||
|
@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
|
||||
while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
|
||||
namedb = namedb->parent;
|
||||
|
||||
handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
|
||||
}
|
||||
|
||||
hprintk(handle, TRACE, "created\n");
|
||||
|
||||
*phandle = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
|
||||
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
nv_device(priv)->chipset == 0xa0) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
|
||||
i += 3;
|
||||
} else {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
|
||||
ctrl = nv_rd32(priv, 0x610798 + (i * 8));
|
||||
i += 3;
|
||||
if (!(ctrl & (1 << head))) {
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
nv_device(priv)->chipset == 0xa0) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
|
||||
i += 4;
|
||||
} else {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
|
||||
ctrl = nv_rd32(priv, 0x610798 + (i * 8));
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ctrl & (1 << head)))
|
||||
return false;
|
||||
i--;
|
||||
|
||||
data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
|
||||
if (data) {
|
||||
@ -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++)
|
||||
ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
|
||||
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
nv_device(priv)->chipset == 0xa0) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
|
||||
i += 3;
|
||||
} else {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
|
||||
ctrl = nv_rd32(priv, 0x610794 + (i * 8));
|
||||
i += 3;
|
||||
if (!(ctrl & (1 << head))) {
|
||||
if (nv_device(priv)->chipset < 0x90 ||
|
||||
nv_device(priv)->chipset == 0x92 ||
|
||||
nv_device(priv)->chipset == 0xa0) {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
|
||||
ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
|
||||
i += 4;
|
||||
} else {
|
||||
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
|
||||
ctrl = nv_rd32(priv, 0x610794 + (i * 8));
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ctrl & (1 << head)))
|
||||
return 0x0000;
|
||||
i--;
|
||||
|
||||
data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
|
||||
if (!data)
|
||||
|
@ -36,6 +36,9 @@ nouveau_client(void *obj)
|
||||
|
||||
int nouveau_client_create_(const char *name, u64 device, const char *cfg,
|
||||
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_fini(struct nouveau_client *, bool suspend);
|
||||
|
||||
|
@ -38,6 +38,8 @@ enum nvbios_pll_type {
|
||||
PLL_UNK42 = 0x42,
|
||||
PLL_VPLL0 = 0x80,
|
||||
PLL_VPLL1 = 0x81,
|
||||
PLL_VPLL2 = 0x82,
|
||||
PLL_VPLL3 = 0x83,
|
||||
PLL_MAX = 0xff
|
||||
};
|
||||
|
||||
|
@ -1534,7 +1534,6 @@ init_io(struct nvbios_init *init)
|
||||
mdelay(10);
|
||||
init_wr32(init, 0x614100, 0x10000018);
|
||||
init_wr32(init, 0x614900, 0x10000018);
|
||||
return;
|
||||
}
|
||||
|
||||
value = init_rdport(init, port) & mask;
|
||||
|
@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
|
||||
switch (info.type) {
|
||||
case PLL_VPLL0:
|
||||
case PLL_VPLL1:
|
||||
case PLL_VPLL2:
|
||||
case PLL_VPLL3:
|
||||
nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
|
||||
nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
|
||||
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,
|
||||
mem->memtype = type;
|
||||
mem->size = size;
|
||||
|
||||
mutex_lock(&mm->mutex);
|
||||
mutex_lock(&pfb->base.mutex);
|
||||
do {
|
||||
if (back)
|
||||
ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
|
||||
else
|
||||
ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
|
||||
if (ret) {
|
||||
mutex_unlock(&mm->mutex);
|
||||
mutex_unlock(&pfb->base.mutex);
|
||||
pfb->ram.put(pfb, &mem);
|
||||
return ret;
|
||||
}
|
||||
@ -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);
|
||||
size -= r->length;
|
||||
} while (size);
|
||||
mutex_unlock(&mm->mutex);
|
||||
mutex_unlock(&pfb->base.mutex);
|
||||
|
||||
r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
|
||||
mem->offset = (u64)r->offset << 12;
|
||||
|
@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&imem->base.mutex);
|
||||
list_add(&iobj->head, &imem->list);
|
||||
mutex_unlock(&imem->base.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_instobj_destroy(struct nouveau_instobj *iobj)
|
||||
{
|
||||
if (iobj->head.prev)
|
||||
list_del(&iobj->head);
|
||||
struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);
|
||||
|
||||
mutex_lock(&subdev->mutex);
|
||||
list_del(&iobj->head);
|
||||
mutex_unlock(&subdev->mutex);
|
||||
|
||||
return nouveau_object_destroy(&iobj->base);
|
||||
}
|
||||
|
||||
@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&imem->base.mutex);
|
||||
|
||||
list_for_each_entry(iobj, &imem->list, head) {
|
||||
if (iobj->suspend) {
|
||||
for (i = 0; i < iobj->size; i += 4)
|
||||
@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&imem->base.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -104,17 +114,26 @@ int
|
||||
nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
|
||||
{
|
||||
struct nouveau_instobj *iobj;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
if (suspend) {
|
||||
mutex_lock(&imem->base.mutex);
|
||||
|
||||
list_for_each_entry(iobj, &imem->list, head) {
|
||||
iobj->suspend = vmalloc(iobj->size);
|
||||
if (iobj->suspend) {
|
||||
for (i = 0; i < iobj->size; i += 4)
|
||||
iobj->suspend[i / 4] = nv_ro32(iobj, i);
|
||||
} else
|
||||
return -ENOMEM;
|
||||
if (!iobj->suspend) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
|
||||
u64 mm_length = (offset + length) - mm_offset;
|
||||
int ret;
|
||||
|
||||
vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL);
|
||||
vm = kzalloc(sizeof(*vm), GFP_KERNEL);
|
||||
if (!vm)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
|
||||
return ret;
|
||||
}
|
||||
|
||||
*pvm = vm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
|
||||
struct nouveau_encoder **pnv_encoder)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nouveau_gpio *gpio = nouveau_gpio(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++) {
|
||||
struct nouveau_i2c_port *port = NULL;
|
||||
struct nouveau_encoder *nv_encoder;
|
||||
struct drm_mode_object *obj;
|
||||
int id;
|
||||
@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
|
||||
port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
|
||||
if (port && nv_probe_i2c(port, 0x50)) {
|
||||
*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 *
|
||||
|
@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev)
|
||||
if (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 */
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
|
||||
|
@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name,
|
||||
struct nouveau_cli *cli;
|
||||
int ret;
|
||||
|
||||
*pcli = NULL;
|
||||
ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
|
||||
nouveau_debug, size, pcli);
|
||||
cli = *pcli;
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (cli)
|
||||
nouveau_client_destroy(&cli->base);
|
||||
*pcli = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&cli->mutex);
|
||||
return 0;
|
||||
|
@ -60,6 +60,7 @@ u32 nv10_fence_read(struct nouveau_channel *);
|
||||
void nv10_fence_context_del(struct nouveau_channel *);
|
||||
void nv10_fence_destroy(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 nv84_fence_create(struct nouveau_drm *);
|
||||
|
@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, 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)
|
||||
|
@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm)
|
||||
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
|
||||
nv10_fence_create(struct nouveau_drm *drm)
|
||||
{
|
||||
@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm)
|
||||
if (ret == 0) {
|
||||
nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
|
||||
priv->base.sync = nv17_fence_sync;
|
||||
priv->base.resume = nv17_fence_resume;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm)
|
||||
if (ret == 0) {
|
||||
nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
|
||||
priv->base.sync = nv17_fence_sync;
|
||||
priv->base.resume = nv17_fence_resume;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
Loading…
Reference in New Issue
Block a user