diff options
Diffstat (limited to 'drivers/gpu/drm')
77 files changed, 1537 insertions, 684 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 738a429..6a64749 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -677,6 +677,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* don't break so fail path works correct */ fail = 1; break; + + if (connector->dpms != DRM_MODE_DPMS_ON) { + DRM_DEBUG_KMS("connector dpms not on, full mode switch\n"); + mode_changed = true; + } } } @@ -754,6 +759,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } + DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); + for (i = 0; i < set->num_connectors; i++) { + DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, + drm_get_connector_name(set->connectors[i])); + set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); + } } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { @@ -771,22 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } } - /* - * crtc set_config helpers implicit set the crtc and all connected - * encoders to DPMS on for a full mode set. But for just an fb update it - * doesn't do that. To not confuse userspace, do an explicit DPMS_ON - * unconditionally. This will also ensure driver internal dpms state is - * consistent again. - */ - if (set->crtc->enabled) { - DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); - for (i = 0; i < set->num_connectors; i++) { - DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, - drm_get_connector_name(set->connectors[i])); - set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); - } - } - kfree(save_connectors); kfree(save_encoders); kfree(save_crtcs); diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index a4f5ce1..271b42b 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -133,8 +133,8 @@ static u8 generic_edid[GENERIC_EDIDS][128] = { }, }; -static u8 *edid_load(struct drm_connector *connector, char *name, - char *connector_name) +static u8 *edid_load(struct drm_connector *connector, const char *name, + const char *connector_name) { const struct firmware *fw; struct platform_device *pdev; @@ -242,7 +242,7 @@ out: int drm_load_edid_firmware(struct drm_connector *connector) { - char *connector_name = drm_get_connector_name(connector); + const char *connector_name = drm_get_connector_name(connector); char *edidname = edid_firmware, *last, *colon; int ret; struct edid *edid; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 0b5af7d..c385cc5 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -92,7 +92,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); if (ret) { - dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret); + dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); kfree(fb_cma); return ERR_PTR(ret); } @@ -376,7 +376,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, ret = drm_fb_helper_initial_config(helper, preferred_bpp); if (ret < 0) { - dev_err(dev->dev, "Failed to set inital hw configuration.\n"); + dev_err(dev->dev, "Failed to set initial hw configuration.\n"); goto err_drm_fb_helper_fini; } diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index ce06397..ece72a8 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -317,288 +317,81 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m EXPORT_SYMBOL_GPL(drm_gem_cma_describe); #endif -/* ----------------------------------------------------------------------------- - * DMA-BUF - */ - -struct drm_gem_cma_dmabuf_attachment { - struct sg_table sgt; - enum dma_data_direction dir; -}; - -static int drm_gem_cma_dmabuf_attach(struct dma_buf *dmabuf, struct device *dev, - struct dma_buf_attachment *attach) -{ - struct drm_gem_cma_dmabuf_attachment *cma_attach; - - cma_attach = kzalloc(sizeof(*cma_attach), GFP_KERNEL); - if (!cma_attach) - return -ENOMEM; - - cma_attach->dir = DMA_NONE; - attach->priv = cma_attach; - - return 0; -} - -static void drm_gem_cma_dmabuf_detach(struct dma_buf *dmabuf, - struct dma_buf_attachment *attach) +/* low-level interface prime helpers */ +struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj) { - struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv; - struct sg_table *sgt; - - if (cma_attach == NULL) - return; - - sgt = &cma_attach->sgt; - - if (cma_attach->dir != DMA_NONE) - dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, - cma_attach->dir); - - sg_free_table(sgt); - kfree(cma_attach); - attach->priv = NULL; -} - -static struct sg_table * -drm_gem_cma_dmabuf_map(struct dma_buf_attachment *attach, - enum dma_data_direction dir) -{ - struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv; - struct drm_gem_cma_object *cma_obj = attach->dmabuf->priv; - struct drm_device *drm = cma_obj->base.dev; - struct scatterlist *rd, *wr; + struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); struct sg_table *sgt; - unsigned int i; - int nents, ret; - - DRM_DEBUG_PRIME("\n"); - - if (WARN_ON(dir == DMA_NONE)) - return ERR_PTR(-EINVAL); - - /* Return the cached mapping when possible. */ - if (cma_attach->dir == dir) - return &cma_attach->sgt; - - /* Two mappings with different directions for the same attachment are - * not allowed. - */ - if (WARN_ON(cma_attach->dir != DMA_NONE)) - return ERR_PTR(-EBUSY); - - sgt = &cma_attach->sgt; - - ret = sg_alloc_table(sgt, cma_obj->sgt->orig_nents, GFP_KERNEL); - if (ret) { - DRM_ERROR("failed to alloc sgt.\n"); - return ERR_PTR(-ENOMEM); - } - - mutex_lock(&drm->struct_mutex); - - rd = cma_obj->sgt->sgl; - wr = sgt->sgl; - for (i = 0; i < sgt->orig_nents; ++i) { - sg_set_page(wr, sg_page(rd), rd->length, rd->offset); - rd = sg_next(rd); - wr = sg_next(wr); - } - - nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); - if (!nents) { - DRM_ERROR("failed to map sgl with iommu.\n"); - sg_free_table(sgt); - sgt = ERR_PTR(-EIO); - goto done; - } + int ret; - cma_attach->dir = dir; - attach->priv = cma_attach; + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return NULL; - DRM_DEBUG_PRIME("buffer size = %zu\n", cma_obj->base.size); + ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr, + cma_obj->paddr, obj->size); + if (ret < 0) + goto out; -done: - mutex_unlock(&drm->struct_mutex); return sgt; -} -static void drm_gem_cma_dmabuf_unmap(struct dma_buf_attachment *attach, - struct sg_table *sgt, - enum dma_data_direction dir) -{ - /* Nothing to do. */ -} - -static void drm_gem_cma_dmabuf_release(struct dma_buf *dmabuf) -{ - struct drm_gem_cma_object *cma_obj = dmabuf->priv; - - DRM_DEBUG_PRIME("%s\n", __FILE__); - - /* - * drm_gem_cma_dmabuf_release() call means that file object's - * f_count is 0 and it calls drm_gem_object_handle_unreference() - * to drop the references that these values had been increased - * at drm_prime_handle_to_fd() - */ - if (cma_obj->base.export_dma_buf == dmabuf) { - cma_obj->base.export_dma_buf = NULL; - - /* - * drop this gem object refcount to release allocated buffer - * and resources. - */ - drm_gem_object_unreference_unlocked(&cma_obj->base); - } +out: + kfree(sgt); + return NULL; } +EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table); -static void *drm_gem_cma_dmabuf_kmap_atomic(struct dma_buf *dmabuf, - unsigned long page_num) +struct drm_gem_object * +drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size, + struct sg_table *sgt) { - /* TODO */ + struct drm_gem_cma_object *cma_obj; - return NULL; -} + if (sgt->nents != 1) + return ERR_PTR(-EINVAL); -static void drm_gem_cma_dmabuf_kunmap_atomic(struct dma_buf *dmabuf, - unsigned long page_num, void *addr) -{ - /* TODO */ -} + /* Create a CMA GEM buffer. */ + cma_obj = __drm_gem_cma_create(dev, size); + if (IS_ERR(cma_obj)) + return ERR_PTR(PTR_ERR(cma_obj)); -static void *drm_gem_cma_dmabuf_kmap(struct dma_buf *dmabuf, - unsigned long page_num) -{ - /* TODO */ + cma_obj->paddr = sg_dma_address(sgt->sgl); + cma_obj->sgt = sgt; - return NULL; -} + DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, size); -static void drm_gem_cma_dmabuf_kunmap(struct dma_buf *dmabuf, - unsigned long page_num, void *addr) -{ - /* TODO */ + return &cma_obj->base; } +EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table); -static int drm_gem_cma_dmabuf_mmap(struct dma_buf *dmabuf, - struct vm_area_struct *vma) +int drm_gem_cma_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma) { - struct drm_gem_cma_object *cma_obj = dmabuf->priv; - struct drm_gem_object *gem_obj = &cma_obj->base; - struct drm_device *dev = gem_obj->dev; + struct drm_gem_cma_object *cma_obj; + struct drm_device *dev = obj->dev; int ret; mutex_lock(&dev->struct_mutex); - ret = drm_gem_mmap_obj(gem_obj, gem_obj->size, vma); + ret = drm_gem_mmap_obj(obj, obj->size, vma); mutex_unlock(&dev->struct_mutex); if (ret < 0) return ret; + cma_obj = to_drm_gem_cma_obj(obj); return drm_gem_cma_mmap_obj(cma_obj, vma); } +EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap); -static void *drm_gem_cma_dmabuf_vmap(struct dma_buf *dmabuf) -{ - struct drm_gem_cma_object *cma_obj = dmabuf->priv; - - return cma_obj->vaddr; -} - -static struct dma_buf_ops drm_gem_cma_dmabuf_ops = { - .attach = drm_gem_cma_dmabuf_attach, - .detach = drm_gem_cma_dmabuf_detach, - .map_dma_buf = drm_gem_cma_dmabuf_map, - .unmap_dma_buf = drm_gem_cma_dmabuf_unmap, - .kmap = drm_gem_cma_dmabuf_kmap, - .kmap_atomic = drm_gem_cma_dmabuf_kmap_atomic, - .kunmap = drm_gem_cma_dmabuf_kunmap, - .kunmap_atomic = drm_gem_cma_dmabuf_kunmap_atomic, - .mmap = drm_gem_cma_dmabuf_mmap, - .vmap = drm_gem_cma_dmabuf_vmap, - .release = drm_gem_cma_dmabuf_release, -}; - -struct dma_buf *drm_gem_cma_dmabuf_export(struct drm_device *drm, - struct drm_gem_object *obj, int flags) +void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj) { struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); - return dma_buf_export(cma_obj, &drm_gem_cma_dmabuf_ops, - cma_obj->base.size, flags); + return cma_obj->vaddr; } -EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_export); +EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vmap); -struct drm_gem_object *drm_gem_cma_dmabuf_import(struct drm_device *drm, - struct dma_buf *dma_buf) +void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr) { - struct drm_gem_cma_object *cma_obj; - struct dma_buf_attachment *attach; - struct sg_table *sgt; - int ret; - - DRM_DEBUG_PRIME("%s\n", __FILE__); - - /* is this one of own objects? */ - if (dma_buf->ops == &drm_gem_cma_dmabuf_ops) { - struct drm_gem_object *obj; - - cma_obj = dma_buf->priv; - obj = &cma_obj->base; - - /* is it from our device? */ - if (obj->dev == drm) { - /* - * Importing dmabuf exported from out own gem increases - * refcount on gem itself instead of f_count of dmabuf. - */ - drm_gem_object_reference(obj); - dma_buf_put(dma_buf); - return obj; - } - } - - /* Create a CMA GEM buffer. */ - cma_obj = __drm_gem_cma_create(drm, dma_buf->size); - if (IS_ERR(cma_obj)) - return ERR_PTR(PTR_ERR(cma_obj)); - - /* Attach to the buffer and map it. Make sure the mapping is contiguous - * on the device memory bus, as that's all we support. - */ - attach = dma_buf_attach(dma_buf, drm->dev); - if (IS_ERR(attach)) { - ret = -EINVAL; - goto error_gem_free; - } - - sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); - if (IS_ERR_OR_NULL(sgt)) { - ret = sgt ? PTR_ERR(sgt) : -ENOMEM; - goto error_buf_detach; - } - - if (sgt->nents != 1) { - ret = -EINVAL; - goto error_buf_unmap; - } - - cma_obj->base.import_attach = attach; - cma_obj->paddr = sg_dma_address(sgt->sgl); - cma_obj->sgt = sgt; - - DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, - dma_buf->size); - - return &cma_obj->base; - -error_buf_unmap: - dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); -error_buf_detach: - dma_buf_detach(dma_buf, attach); -error_gem_free: - drm_gem_cma_free_object(&cma_obj->base); - return ERR_PTR(ret); + /* Nothing to do */ } -EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_import); +EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vunmap); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 1e0de41..85e450e 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -119,12 +119,13 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf, return; sgt = prime_attach->sgt; + if (sgt) { + if (prime_attach->dir != DMA_NONE) + dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, + prime_attach->dir); + sg_free_table(sgt); + } - if (prime_attach->dir != DMA_NONE) - dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, - prime_attach->dir); - - sg_free_table(sgt); kfree(sgt); kfree(prime_attach); attach->priv = NULL; @@ -244,7 +245,13 @@ static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) { - return -EINVAL; + struct drm_gem_object *obj = dma_buf->priv; + struct drm_device *dev = obj->dev; + + if (!dev->driver->gem_prime_mmap) + return -ENOSYS; + + return dev->driver->gem_prime_mmap(obj, vma); } static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 22865ba..b8ac06d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -57,8 +57,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, dma_addr_t start_addr; unsigned int i = 0; - buf->pages = kzalloc(sizeof(struct page) * nr_pages, - GFP_KERNEL); + buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); if (!buf->pages) { DRM_ERROR("failed to allocate pages.\n"); return -ENOMEM; @@ -69,8 +68,8 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, &buf->dma_attrs); if (!buf->kvaddr) { DRM_ERROR("failed to allocate buffer.\n"); - kfree(buf->pages); - return -ENOMEM; + ret = -ENOMEM; + goto err_free; } start_addr = buf->dma_addr; @@ -107,9 +106,9 @@ err_free_attrs: dma_free_attrs(dev->dev, buf->size, buf->pages, (dma_addr_t)buf->dma_addr, &buf->dma_attrs); buf->dma_addr = (dma_addr_t)NULL; - +err_free: if (!is_drm_iommu_supported(dev)) - kfree(buf->pages); + drm_free_large(buf->pages); return ret; } @@ -134,7 +133,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev, if (!is_drm_iommu_supported(dev)) { dma_free_attrs(dev->dev, buf->size, buf->kvaddr, (dma_addr_t)buf->dma_addr, &buf->dma_attrs); - kfree(buf->pages); + drm_free_large(buf->pages); } else dma_free_attrs(dev->dev, buf->size, buf->pages, (dma_addr_t)buf->dma_addr, &buf->dma_attrs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2762373..ca2729a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -155,6 +155,7 @@ static int exynos_drm_unload(struct drm_device *dev) static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv; + int ret; file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) @@ -162,7 +163,13 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; - return exynos_drm_subdrv_open(dev, file); + ret = exynos_drm_subdrv_open(dev, file); + if (ret) { + kfree(file_priv); + file->driver_priv = NULL; + } + + return ret; } static void exynos_drm_preclose(struct drm_device *dev, diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index af75434..42a5a54 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -388,12 +388,9 @@ out: sg_free_table(g2d_userptr->sgt); kfree(g2d_userptr->sgt); - g2d_userptr->sgt = NULL; - kfree(g2d_userptr->pages); - g2d_userptr->pages = NULL; + drm_free_large(g2d_userptr->pages); kfree(g2d_userptr); - g2d_userptr = NULL; } static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, @@ -463,11 +460,11 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, npages = (end - start) >> PAGE_SHIFT; g2d_userptr->npages = npages; - pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL); + pages = drm_calloc_large(npages, sizeof(struct page *)); if (!pages) { DRM_ERROR("failed to allocate pages.\n"); - kfree(g2d_userptr); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_free; } vma = find_vma(current->mm, userptr); @@ -543,7 +540,6 @@ err_sg_free_table: err_free_sgt: kfree(sgt); - sgt = NULL; err_free_userptr: exynos_gem_put_pages_to_userptr(g2d_userptr->pages, @@ -554,10 +550,10 @@ err_put_vma: exynos_gem_put_vma(g2d_userptr->vma); err_free_pages: - kfree(pages); + drm_free_large(pages); + +err_free: kfree(g2d_userptr); - pages = NULL; - g2d_userptr = NULL; return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index c3f15e7..24c22a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -246,13 +246,14 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, exynos_gem_obj->flags = flags; ret = exynos_drm_alloc_buf(dev, buf, flags); - if (ret < 0) { - drm_gem_object_release(&exynos_gem_obj->base); - goto err_fini_buf; - } + if (ret < 0) + goto err_gem_fini; return exynos_gem_obj; +err_gem_fini: + drm_gem_object_release(&exynos_gem_obj->base); + kfree(exynos_gem_obj); err_fini_buf: exynos_drm_fini_buf(dev, buf); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 784bbce..41cc74d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -413,9 +413,6 @@ static int vidi_power_on(struct vidi_context *ctx, bool enable) struct exynos_drm_subdrv *subdrv = &ctx->subdrv; struct device *dev = subdrv->dev; - if (enable != false && enable != true) - return -EINVAL; - if (enable) { ctx->suspended = false; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index b1280b4..42ffb71 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -379,7 +379,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) unsigned long flags; struct hdmi_win_data *win_data; unsigned int x_ratio, y_ratio; - unsigned int buf_num; + unsigned int buf_num = 1; dma_addr_t luma_addr[2], chroma_addr[2]; bool tiled_mode = false; bool crcb_mode = false; diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 004ecdf..ada49ed 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -97,7 +97,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) buf = dev_priv->mmap_buffer; buf_priv = buf->dev_private; - vma->vm_flags |= (VM_IO | VM_DONTCOPY); + vma->vm_flags |= VM_DONTCOPY; buf_priv->currently_mapped = I810_BUF_MAPPED; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index adb319b..cf188ab 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1648,7 +1648,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (INTEL_INFO(dev)->num_pipes) { /* Must be done after probing outputs */ intel_opregion_init(dev); - acpi_video_register(); + acpi_video_register_with_quirks(); } if (IS_GEN5(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 062cbda..f4af1ca 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -123,10 +123,10 @@ module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 060 MODULE_PARM_DESC(preliminary_hw_support, "Enable preliminary hardware support. (default: false)"); -int i915_disable_power_well __read_mostly = 0; +int i915_disable_power_well __read_mostly = 1; module_param_named(disable_power_well, i915_disable_power_well, int, 0600); MODULE_PARM_DESC(disable_power_well, - "Disable the power well when possible (default: false)"); + "Disable the power well when possible (default: true)"); int i915_enable_ips __read_mostly = 1; module_param_named(enable_ips, i915_enable_ips, int, 0600); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cc1d605..a416645 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1806,6 +1806,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gem_obj, int flags); +void i915_gem_restore_fences(struct drm_device *dev); + /* i915_gem_context.c */ void i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 769f752..97afd26 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1880,6 +1880,10 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, u32 seqno = intel_ring_get_seqno(ring); BUG_ON(ring == NULL); + if (obj->ring != ring && obj->last_write_seqno) { + /* Keep the seqno relative to the current ring */ + obj->last_write_seqno = seqno; + } obj->ring = ring; /* Add a reference if we're newly entering the active list. */ @@ -2247,25 +2251,15 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, } } -static void i915_gem_reset_fences(struct drm_device *dev) +void i915_gem_restore_fences(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int i; for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - - if (reg->obj) - i915_gem_object_fence_lost(reg->obj); - - i915_gem_write_fence(dev, i, NULL); - - reg->pin_count = 0; - reg->obj = NULL; - INIT_LIST_HEAD(®->lru_list); + i915_gem_write_fence(dev, i, reg->obj); } - - INIT_LIST_HEAD(&dev_priv->mm.fence_list); } void i915_gem_reset(struct drm_device *dev) @@ -2288,8 +2282,7 @@ void i915_gem_reset(struct drm_device *dev) obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; } - /* The fence registers are invalidated so clear them out */ - i915_gem_reset_fences(dev); + i915_gem_restore_fences(dev); } /** @@ -2664,7 +2657,6 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, drm_i915_private_t *dev_priv = dev->dev_private; int fence_reg; int fence_pitch_shift; - uint64_t val; if (INTEL_INFO(dev)->gen >= 6) { fence_reg = FENCE_REG_SANDYBRIDGE_0; @@ -2674,8 +2666,23 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, fence_pitch_shift = I965_FENCE_PITCH_SHIFT; } + fence_reg += reg * 8; + + /* To w/a incoherency with non-atomic 64-bit register updates, + * we split the 64-bit update into two 32-bit writes. In order + * for a partial fence not to be evaluated between writes, we + * precede the update with write to turn off the fence register, + * and only enable the fence as the last step. + * + * For extra levels of paranoia, we make sure each step lands + * before applying the next step. + */ + I915_WRITE(fence_reg, 0); + POSTING_READ(fence_reg); + if (obj) { u32 size = obj->gtt_space->size; + uint64_t val; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; @@ -2684,12 +2691,16 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - } else - val = 0; - fence_reg += reg * 8; - I915_WRITE64(fence_reg, val); - POSTING_READ(fence_reg); + I915_WRITE(fence_reg + 4, val >> 32); + POSTING_READ(fence_reg + 4); + + I915_WRITE(fence_reg + 0, val); + POSTING_READ(fence_reg); + } else { + I915_WRITE(fence_reg + 4, 0); + POSTING_READ(fence_reg + 4); + } } static void i915_write_fence_reg(struct drm_device *dev, int reg, @@ -2807,56 +2818,17 @@ static inline int fence_number(struct drm_i915_private *dev_priv, return fence - dev_priv->fence_regs; } -struct write_fence { - struct drm_device *dev; - struct drm_i915_gem_object *obj; - int fence; -}; - -static void i915_gem_write_fence__ipi(void *data) -{ - struct write_fence *args = data; - - /* Required for SNB+ with LLC */ - wbinvd(); - - /* Required for VLV */ - i915_gem_write_fence(args->dev, args->fence, args->obj); -} - static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct write_fence args = { - .dev = obj->base.dev, - .fence = fence_number(dev_priv, fence), - .obj = enable ? obj : NULL, - }; - - /* In order to fully serialize access to the fenced region and - * the update to the fence register we need to take extreme - * measures on SNB+. In theory, the write to the fence register - * flushes all memory transactions before, and coupled with the - * mb() placed around the register write we serialise all memory - * operations with respect to the changes in the tiler. Yet, on - * SNB+ we need to take a step further and emit an explicit wbinvd() - * on each processor in order to manually flush all memory - * transactions before updating the fence register. - * - * However, Valleyview complicates matter. There the wbinvd is - * insufficient and unlike SNB/IVB requires the serialising - * register write. (Note that that register write by itself is - * conversely not sufficient for SNB+.) To compromise, we do both. - */ - if (INTEL_INFO(args.dev)->gen >= 6) - on_each_cpu(i915_gem_write_fence__ipi, &args, 1); - else - i915_gem_write_fence(args.dev, args.fence, args.obj); + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); if (enable) { - obj->fence_reg = args.fence; + obj->fence_reg = reg; fence->obj = obj; list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); } else { @@ -4020,8 +3992,6 @@ i915_gem_idle(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_gem_evict_everything(dev); - i915_gem_reset_fences(dev); - /* Hack! Don't let anybody do execbuf while we don't control the chip. * We need to replace this with a semaphore, or something. * And not confound mm.suspended! @@ -4357,7 +4327,8 @@ i915_gem_load(struct drm_device *dev) dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ - i915_gem_reset_fences(dev); + INIT_LIST_HEAD(&dev_priv->mm.fence_list); + i915_gem_restore_fences(dev); i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); @@ -4623,7 +4594,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) if (obj->pages_pin_count == 0) cnt += obj->base.size >> PAGE_SHIFT; - list_for_each_entry(obj, &dev_priv->mm.inactive_list, global_list) + list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) if (obj->pin_count == 0 && obj->pages_pin_count == 0) cnt += obj->base.size >> PAGE_SHIFT; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 88b9a66..70db618 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -394,6 +394,7 @@ int i915_restore_state(struct drm_device *dev) mutex_lock(&dev->struct_mutex); + i915_gem_restore_fences(dev); i915_restore_display(dev); if (!drm_core_check_feature(dev, DRIVER_MODESET)) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b739712..26e162b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -75,7 +75,12 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp) case DP_LINK_BW_1_62: case DP_LINK_BW_2_7: break; + case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */ + max_link_bw = DP_LINK_BW_2_7; + break; default: + WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n", + max_link_bw); max_link_bw = DP_LINK_BW_1_62; break; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2abb2d3..021e8da 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -690,6 +690,22 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Intel D510MO", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Intel D525MW", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ccbdd83..d10e673 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5500,9 +5500,38 @@ void intel_gt_init(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) { dev_priv->gt.force_wake_get = vlv_force_wake_get; dev_priv->gt.force_wake_put = vlv_force_wake_put; - } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { + } else if (IS_HASWELL(dev)) { dev_priv->gt.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->gt.force_wake_put = __gen6_gt_force_wake_mt_put; + } else if (IS_IVYBRIDGE(dev)) { + u32 ecobus; + + /* IVB configs may use multi-threaded forcewake */ + + /* A small trick here - if the bios hasn't configured + * MT forcewake, and if the device is in RC6, then + * force_wake_mt_get will not wake the device and the + * ECOBUS read will return zero. Which will be + * (correctly) interpreted by the test below as MT + * forcewake being disabled. + */ + mutex_lock(&dev->struct_mutex); + __gen6_gt_force_wake_mt_get(dev_priv); + ecobus = I915_READ_NOTRACE(ECOBUS); + __gen6_gt_force_wake_mt_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + if (ecobus & FORCEWAKE_MT_ENABLE) { + dev_priv->gt.force_wake_get = + __gen6_gt_force_wake_mt_get; + dev_priv->gt.force_wake_put = + __gen6_gt_force_wake_mt_put; + } else { + DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); + DRM_INFO("when using vblank-synced partial screen updates.\n"); + dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; + dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; + } } else if (IS_GEN6(dev)) { dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e51ab55..664118d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -379,6 +379,17 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) return I915_READ(acthd_reg); } +static void ring_setup_phys_status_page(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + u32 addr; + + addr = dev_priv->status_page_dmah->busaddr; + if (INTEL_INFO(ring->dev)->gen >= 4) + addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); +} + static int init_ring_common(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -390,6 +401,11 @@ static int init_ring_common(struct intel_ring_buffer *ring) if (HAS_FORCE_WAKE(dev)) gen6_gt_force_wake_get(dev_priv); + if (I915_NEED_GFX_HWS(dev)) + intel_ring_setup_status_page(ring); + else + ring_setup_phys_status_page(ring); + /* Stop the ring if it's running. */ I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); @@ -518,9 +534,6 @@ cleanup_pipe_control(struct intel_ring_buffer *ring) struct pipe_control *pc = ring->private; struct drm_i915_gem_object *obj; - if (!ring->private) - return; - obj = pc->obj; kunmap(sg_page(obj->pages->sgl)); @@ -528,7 +541,6 @@ cleanup_pipe_control(struct intel_ring_buffer *ring) drm_gem_object_unreference(&obj->base); kfree(pc); - ring->private = NULL; } static int init_render_ring(struct intel_ring_buffer *ring) @@ -601,7 +613,10 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring) if (HAS_BROKEN_CS_TLB(dev)) drm_gem_object_unreference(to_gem_object(ring->private)); - cleanup_pipe_control(ring); + if (INTEL_INFO(dev)->gen >= 5) + cleanup_pipe_control(ring); + + ring->private = NULL; } static void @@ -1223,7 +1238,6 @@ static int init_status_page(struct intel_ring_buffer *ring) ring->status_page.obj = obj; memset(ring->status_page.page_addr, 0, PAGE_SIZE); - intel_ring_setup_status_page(ring); DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", ring->name, ring->status_page.gfx_addr); @@ -1237,10 +1251,9 @@ err: return ret; } -static int init_phys_hws_pga(struct intel_ring_buffer *ring) +static int init_phys_status_page(struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - u32 addr; if (!dev_priv->status_page_dmah) { dev_priv->status_page_dmah = @@ -1249,11 +1262,6 @@ static int init_phys_hws_pga(struct intel_ring_buffer *ring) return -ENOMEM; } - addr = dev_priv->status_page_dmah->busaddr; - if (INTEL_INFO(ring->dev)->gen >= 4) - addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; - I915_WRITE(HWS_PGA, addr); - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; memset(ring->status_page.page_addr, 0, PAGE_SIZE); @@ -1281,7 +1289,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, return ret; } else { BUG_ON(ring->id != RCS); - ret = init_phys_hws_pga(ring); + ret = init_phys_status_page(ring); if (ret) return ret; } @@ -1893,7 +1901,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) } if (!I915_NEED_GFX_HWS(dev)) { - ret = init_phys_hws_pga(ring); + ret = init_phys_status_page(ring); if (ret) return ret; } diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index ef161ea..11a5263 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -40,7 +40,7 @@ struct omap_crtc { * mgr->id.) Eventually this will be replaced w/ something * more common-panel-framework-y */ - struct omap_overlay_manager mgr; + struct omap_overlay_manager *mgr; struct omap_video_timings timings; bool enabled; @@ -90,7 +90,32 @@ uint32_t pipe2vbl(struct drm_crtc *crtc) * job of sequencing the setup of the video pipe in the proper order */ +/* ovl-mgr-id -> crtc */ +static struct omap_crtc *omap_crtcs[8]; + /* we can probably ignore these until we support command-mode panels: */ +static int omap_crtc_connect(struct omap_overlay_manager *mgr, + struct omap_dss_device *dst) +{ + if (mgr->output) + return -EINVAL; + + if ((mgr->supported_outputs & dst->id) == 0) + return -EINVAL; + + dst->manager = mgr; + mgr->output = dst; + + return 0; +} + +static void omap_crtc_disconnect(struct omap_overlay_manager *mgr, + struct omap_dss_device *dst) +{ + mgr->output->manager = NULL; + mgr->output = NULL; +} + static void omap_crtc_start_update(struct omap_overlay_manager *mgr) { } @@ -107,7 +132,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr) static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, const struct omap_video_timings *timings) { - struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; DBG("%s", omap_crtc->name); omap_crtc->timings = *timings; omap_crtc->full_update = true; @@ -116,7 +141,7 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, const struct dss_lcd_mgr_config *config) { - struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; DBG("%s", omap_crtc->name); dispc_mgr_set_lcd_config(omap_crtc->channel, config); } @@ -135,6 +160,8 @@ static void omap_crtc_unregister_framedone_handler( } static const struct dss_mgr_ops mgr_ops = { + .connect = omap_crtc_connect, + .disconnect = omap_crtc_disconnect, .start_update = omap_crtc_start_update, .enable = omap_crtc_enable, .disable = omap_crtc_disable, @@ -564,7 +591,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) } else { if (encoder) { omap_encoder_set_enabled(encoder, false); - omap_encoder_update(encoder, &omap_crtc->mgr, + omap_encoder_update(encoder, omap_crtc->mgr, &omap_crtc->timings); omap_encoder_set_enabled(encoder, true); omap_crtc->full_update = false; @@ -590,6 +617,11 @@ static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD2] = "lcd2", }; +void omap_crtc_pre_init(void) +{ + dss_install_mgr_ops(&mgr_ops); +} + /* initialize crtc */ struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, enum omap_channel channel, int id) @@ -630,9 +662,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_irq_register(dev, &omap_crtc->error_irq); /* temporary: */ - omap_crtc->mgr.id = channel; - - dss_install_mgr_ops(&mgr_ops); + omap_crtc->mgr = omap_dss_get_overlay_manager(channel); /* TODO: fix hard-coded setup.. add properties! */ info = &omap_crtc->info; @@ -646,6 +676,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_plane_install_properties(omap_crtc->plane, &crtc->base); + omap_crtcs[channel] = omap_crtc; + return crtc; fail: diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 826586f..a3004f1 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -65,10 +65,8 @@ static int get_connector_type(struct omap_dss_device *dssdev) switch (dssdev->type) { case OMAP_DISPLAY_TYPE_HDMI: return DRM_MODE_CONNECTOR_HDMIA; - case OMAP_DISPLAY_TYPE_DPI: - if (!strcmp(dssdev->name, "dvi")) - return DRM_MODE_CONNECTOR_DVID; - /* fallthrough */ + case OMAP_DISPLAY_TYPE_DVI: + return DRM_MODE_CONNECTOR_DVID; default: return DRM_MODE_CONNECTOR_Unknown; } @@ -97,6 +95,9 @@ static int omap_modeset_init(struct drm_device *dev) int num_mgrs = dss_feat_get_num_mgrs(); int num_crtcs; int i, id = 0; + int r; + + omap_crtc_pre_init(); drm_mode_config_init(dev); @@ -116,6 +117,7 @@ static int omap_modeset_init(struct drm_device *dev) struct drm_connector *connector; struct drm_encoder *encoder; enum omap_channel channel; + struct omap_overlay_manager *mgr; if (!dssdev->driver) { dev_warn(dev->dev, "%s has no driver.. skipping it\n", @@ -131,6 +133,13 @@ static int omap_modeset_init(struct drm_device *dev) continue; } + r = dssdev->driver->connect(dssdev); + if (r) { + dev_err(dev->dev, "could not connect display: %s\n", + dssdev->name); + continue; + } + encoder = omap_encoder_init(dev, dssdev); if (!encoder) { @@ -172,8 +181,9 @@ static int omap_modeset_init(struct drm_device *dev) * other possible channels to which the encoder can connect are * not considered. */ - channel = dssdev->output->dispc_channel; + mgr = omapdss_find_mgr_from_display(dssdev); + channel = mgr->id; /* * if this channel hasn't already been taken by a previously * allocated crtc, we create a new crtc for it @@ -247,6 +257,9 @@ static int omap_modeset_init(struct drm_device *dev) struct drm_encoder *encoder = priv->encoders[i]; struct omap_dss_device *dssdev = omap_encoder_get_dssdev(encoder); + struct omap_dss_device *output; + + output = omapdss_find_output_from_display(dssdev); /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; @@ -259,9 +272,11 @@ static int omap_modeset_init(struct drm_device *dev) supported_outputs = dss_feat_get_supported_outputs(crtc_channel); - if (supported_outputs & dssdev->output->id) + if (supported_outputs & output->id) encoder->possible_crtcs |= (1 << id); } + + omap_dss_put_device(output); } DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 215a20d..14f17da 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -157,6 +157,7 @@ const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); int omap_crtc_apply(struct drm_crtc *crtc, struct omap_drm_apply *apply); +void omap_crtc_pre_init(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, enum omap_channel channel, int id); diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 6ba49d9..27f45e4 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -171,6 +171,11 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info)) return -EINVAL; + if (!access_ok(VERIFY_READ, + (void *)(unsigned long)user_cmd.command, + user_cmd.command_size)) + return -EFAULT; + ret = qxl_alloc_release_reserved(qdev, sizeof(union qxl_release_info) + user_cmd.command_size, diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index c7ad4b9..b9d3b43 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1841,6 +1841,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, atombios_crtc_set_base(crtc, x, y, old_fb); atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_scaler_setup(crtc); + /* update the hw version fpr dpm */ + radeon_crtc->hw_mode = *adjusted_mode; + return 0; } diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index f072660..0bfd55e 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2059,6 +2059,19 @@ static void btc_init_stutter_mode(struct radeon_device *rdev) } } +bool btc_dpm_vblank_too_short(struct radeon_device *rdev) +{ + struct rv7xx_power_info *pi = rv770_get_pi(rdev); + u32 vblank_time = r600_dpm_get_vblank_time(rdev); + u32 switch_limit = pi->mem_gddr5 ? 450 : 100; + + if (vblank_time < switch_limit) + return true; + else + return false; + +} + static void btc_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2068,7 +2081,8 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev, u32 mclk, sclk; u16 vddc, vddci; - if (rdev->pm.dpm.new_active_crtc_count > 1) + if ((rdev->pm.dpm.new_active_crtc_count > 1) || + btc_dpm_vblank_too_short(rdev)) disable_mclk_switching = true; else disable_mclk_switching = false; @@ -2326,9 +2340,9 @@ int btc_dpm_set_power_state(struct radeon_device *rdev) return ret; } - ret = rv770_unrestrict_performance_levels_after_switch(rdev); + ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { - DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n"); + DRM_ERROR("rv770_dpm_force_performance_level failed\n"); return ret; } diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index ed1d910..6dacec4 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include "drmP.h" @@ -742,7 +741,6 @@ static int ci_mc_load_microcode(struct radeon_device *rdev) */ static int cik_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; size_t pfp_req_size, me_req_size, ce_req_size, mec_req_size, rlc_req_size, mc_req_size, @@ -752,13 +750,6 @@ static int cik_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_BONAIRE: chip_name = "BONAIRE"; @@ -794,7 +785,7 @@ static int cik_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -806,7 +797,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -817,7 +808,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); - err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->ce_fw->size != ce_req_size) { @@ -828,7 +819,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); - err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mec_fw->size != mec_req_size) { @@ -839,7 +830,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -850,7 +841,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); - err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->sdma_fw->size != sdma_req_size) { @@ -863,7 +854,7 @@ static int cik_init_microcode(struct radeon_device *rdev) /* No MC ucode on APUs */ if (!(rdev->flags & RADEON_IS_IGP)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -875,8 +866,6 @@ static int cik_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -4453,6 +4442,29 @@ void cik_vm_fini(struct radeon_device *rdev) } /** + * cik_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (CIK). + */ +static void cik_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr, u32 mc_client) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block = (char *)&mc_client; + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + +/** * cik_vm_flush - cik vm flush using the CP * * @rdev: radeon_device pointer @@ -5507,6 +5519,7 @@ int cik_irq_process(struct radeon_device *rdev) u32 ring_index; bool queue_hotplug = false; bool queue_reset = false; + u32 addr, status, mc_client; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -5742,11 +5755,15 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); + mc_client = RREG32(VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + cik_vm_decode_fault(rdev, status, addr, mc_client); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; @@ -6961,7 +6978,7 @@ int cik_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 63514b9..7e9275e 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -136,6 +136,22 @@ #define VM_INVALIDATE_RESPONSE 0x147c #define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 1: pde0 + * bit 2: valid + * bit 3: read + * bit 4: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0xf << 25) +#define FAULT_VMID_SHIFT 25 + +#define VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT 0x14E4 #define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 5ada922..9bcdd17 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -2014,9 +2014,9 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev) if (eg_pi->pcie_performance_request) cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); - ret = rv770_unrestrict_performance_levels_after_switch(rdev); + ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { - DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n"); + DRM_ERROR("rv770_dpm_force_performance_level failed\n"); return ret; } @@ -2174,3 +2174,16 @@ void cypress_dpm_fini(struct radeon_device *rdev) kfree(rdev->pm.dpm.ps); kfree(rdev->pm.dpm.priv); } + +bool cypress_dpm_vblank_too_short(struct radeon_device *rdev) +{ + struct rv7xx_power_info *pi = rv770_get_pi(rdev); + u32 vblank_time = r600_dpm_get_vblank_time(rdev); + u32 switch_limit = pi->mem_gddr5 ? 450 : 300; + + if (vblank_time < switch_limit) + return true; + else + return false; + +} diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 2e1de4f..038dcac 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -139,6 +139,8 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev); void evergreen_program_aspm(struct radeon_device *rdev); extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev, int ring, u32 cp_int_cntl); +extern void cayman_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr); static const u32 evergreen_golden_registers[] = { @@ -1504,8 +1506,8 @@ void evergreen_pm_misc(struct radeon_device *rdev) struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if (voltage->type == VOLTAGE_SW) { - /* 0xff01 is a flag rather then an actual voltage */ - if (voltage->voltage == 0xff01) + /* 0xff0x are flags rather then an actual voltage */ + if ((voltage->voltage & 0xff00) == 0xff00) return; if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); @@ -1525,8 +1527,8 @@ void evergreen_pm_misc(struct radeon_device *rdev) voltage = &rdev->pm.power_state[req_ps_idx]. clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage; - /* 0xff01 is a flag rather then an actual voltage */ - if (voltage->vddci == 0xff01) + /* 0xff0x are flags rather then an actual voltage */ + if ((voltage->vddci & 0xff00) == 0xff00) return; if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) { radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI); @@ -4586,6 +4588,7 @@ int evergreen_irq_process(struct radeon_device *rdev) bool queue_hotplug = false; bool queue_hdmi = false; bool queue_thermal = false; + u32 status, addr; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -4872,11 +4875,14 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + cayman_vm_decode_fault(rdev, status, addr); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; @@ -5509,6 +5515,9 @@ void evergreen_program_aspm(struct radeon_device *rdev) */ bool fusion_platform = false; + if (radeon_aspm == 0) + return; + if (!(rdev->flags & RADEON_IS_PCIE)) return; diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index b9c6f76..b0d3fb3 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -177,6 +177,9 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode uint32_t offset; ssize_t err; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (!dig->afmt->enabled) return; @@ -280,6 +283,9 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (enable && dig->afmt->enabled) return; diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index 5a82b6b..af85299 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -373,19 +373,6 @@ static inline void list_splice_tail_init(struct list_head *list, pos = pos->next) /** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index f30127c..56bd4f3 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include <drm/drmP.h> @@ -684,7 +683,6 @@ int ni_mc_load_microcode(struct radeon_device *rdev) int ni_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size; @@ -694,13 +692,6 @@ int ni_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_BARTS: chip_name = "BARTS"; @@ -753,7 +744,7 @@ int ni_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -765,7 +756,7 @@ int ni_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -776,7 +767,7 @@ int ni_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -789,7 +780,7 @@ int ni_init_microcode(struct radeon_device *rdev) /* no MC ucode on TN */ if (!(rdev->flags & RADEON_IS_IGP)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -802,7 +793,7 @@ int ni_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -814,8 +805,6 @@ int ni_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -2461,6 +2450,167 @@ void cayman_vm_fini(struct radeon_device *rdev) { } +/** + * cayman_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (cayman/TN). + */ +void cayman_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block; + + switch (mc_id) { + case 32: + case 16: + case 96: + case 80: + case 160: + case 144: + case 224: + case 208: + block = "CB"; + break; + case 33: + case 17: + case 97: + case 81: + case 161: + case 145: + case 225: + case 209: + block = "CB_FMASK"; + break; + case 34: + case 18: + case 98: + case 82: + case 162: + case 146: + case 226: + case 210: + block = "CB_CMASK"; + break; + case 35: + case 19: + case 99: + case 83: + case 163: + case 147: + case 227: + case 211: + block = "CB_IMMED"; + break; + case 36: + case 20: + case 100: + case 84: + case 164: + case 148: + case 228: + case 212: + block = "DB"; + break; + case 37: + case 21: + case 101: + case 85: + case 165: + case 149: + case 229: + case 213: + block = "DB_HTILE"; + break; + case 38: + case 22: + case 102: + case 86: + case 166: + case 150: + case 230: + case 214: + block = "SX"; + break; + case 39: + case 23: + case 103: + case 87: + case 167: + case 151: + case 231: + case 215: + block = "DB_STEN"; + break; + case 40: + case 24: + case 104: + case 88: + case 232: + case 216: + case 168: + case 152: + block = "TC_TFETCH"; + break; + case 41: + case 25: + case 105: + case 89: + case 233: + case 217: + case 169: + case 153: + block = "TC_VFETCH"; + break; + case 42: + case 26: + case 106: + case 90: + case 234: + case 218: + case 170: + case 154: + block = "VC"; + break; + case 112: + block = "CP"; + break; + case 113: + case 114: + block = "SH"; + break; + case 115: + block = "VGT"; + break; + case 178: + block = "IH"; + break; + case 51: + block = "RLC"; + break; + case 55: + block = "DMA"; + break; + case 56: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + #define R600_ENTRY_VALID (1 << 0) #define R600_PTE_SYSTEM (1 << 1) #define R600_PTE_SNOOPED (1 << 2) diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index a4cb99c..559cf24 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -765,6 +765,19 @@ static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev, ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage); } +bool ni_dpm_vblank_too_short(struct radeon_device *rdev) +{ + struct rv7xx_power_info *pi = rv770_get_pi(rdev); + u32 vblank_time = r600_dpm_get_vblank_time(rdev); + u32 switch_limit = pi->mem_gddr5 ? 450 : 300; + + if (vblank_time < switch_limit) + return true; + else + return false; + +} + static void ni_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -775,7 +788,8 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev, u16 vddc, vddci; int i; - if (rdev->pm.dpm.new_active_crtc_count > 1) + if ((rdev->pm.dpm.new_active_crtc_count > 1) || + ni_dpm_vblank_too_short(rdev)) disable_mclk_switching = true; else disable_mclk_switching = false; @@ -1037,13 +1051,37 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd 0 : -EINVAL; } -static int ni_unrestrict_performance_levels_after_switch(struct radeon_device *rdev) +int ni_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) { - if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) - return -EINVAL; + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct ni_ps *ps = ni_get_ps(rps); + u32 levels; - return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) == PPSMC_Result_OK) ? - 0 : -EINVAL; + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK) + return -EINVAL; + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + levels = ps->performance_level_count - 1; + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) + return -EINVAL; + } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + } + + rdev->pm.dpm.forced_level = level; + + return 0; } static void ni_stop_smc(struct radeon_device *rdev) @@ -3831,9 +3869,9 @@ int ni_dpm_set_power_state(struct radeon_device *rdev) return ret; } - ret = ni_unrestrict_performance_levels_after_switch(rdev); + ret = ni_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { - DRM_ERROR("ni_unrestrict_performance_levels_after_switch failed\n"); + DRM_ERROR("ni_dpm_force_performance_level failed\n"); return ret; } diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h index ac1c7ab..6bbee91 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.h +++ b/drivers/gpu/drm/radeon/ni_dpm.h @@ -245,4 +245,6 @@ void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, struct radeon_ps *new_ps, struct radeon_ps *old_ps); +bool ni_dpm_vblank_too_short(struct radeon_device *rdev); + #endif diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index fe24a93..22421bc 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -133,6 +133,22 @@ #define VM_CONTEXT1_CNTL2 0x1434 #define VM_INVALIDATE_REQUEST 0x1478 #define VM_INVALIDATE_RESPONSE 0x147c +#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC +#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 2: pde0 + * bit 3: valid + * bit 4: read + * bit 5: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0x7 << 25) +#define FAULT_VMID_SHIFT 25 #define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 #define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR 0x151c #define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h index 8fb1113..b5564a3 100644 --- a/drivers/gpu/drm/radeon/ppsmc.h +++ b/drivers/gpu/drm/radeon/ppsmc.h @@ -71,6 +71,8 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_SwitchToSwState ((uint8_t)0x20) #define PPSMC_MSG_SwitchToInitialState ((uint8_t)0x40) #define PPSMC_MSG_NoForcedLevel ((uint8_t)0x41) +#define PPSMC_MSG_ForceHigh ((uint8_t)0x42) +#define PPSMC_MSG_ForceMediumOrHigh ((uint8_t)0x43) #define PPSMC_MSG_SwitchToMinimumPower ((uint8_t)0x51) #define PPSMC_MSG_ResumeFromMinimumPower ((uint8_t)0x52) #define PPSMC_MSG_EnableCac ((uint8_t)0x53) @@ -101,6 +103,7 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_DPM_Config ((uint32_t) 0x102) #define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104) #define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) +#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) #define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) #define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) #define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index d0314ec..75349cd 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -39,7 +39,6 @@ #include "atom.h" #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/module.h> #include "r100_reg_safe.h" @@ -989,18 +988,11 @@ void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) /* Load the microcode for the CP */ static int r100_cp_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *fw_name = NULL; int err; DRM_DEBUG_KMS("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || (rdev->family == CHIP_RS200)) { @@ -1042,8 +1034,7 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) fw_name = FIRMWARE_R520; } - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); - platform_device_unregister(pdev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) { printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n", fw_name); @@ -3077,6 +3068,10 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg, flags |= RADEON_SURF_TILE_COLOR_BOTH; if (tiling_flags & RADEON_TILING_MACRO) flags |= RADEON_SURF_TILE_COLOR_MACRO; + /* setting pitch to 0 disables tiling */ + if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) + == 0) + pitch = 0; } else if (rdev->family <= CHIP_RV280) { if (tiling_flags & (RADEON_TILING_MACRO)) flags |= R200_SURF_TILE_COLOR_MACRO; @@ -3094,13 +3089,6 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg, if (tiling_flags & RADEON_TILING_SWAP_32BIT) flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP; - /* when we aren't tiling the pitch seems to needs to be furtherdivided down. - tested on power5 + rn50 server */ - if (tiling_flags & (RADEON_TILING_SWAP_16BIT | RADEON_TILING_SWAP_32BIT)) { - if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) - if (ASIC_IS_RN50(rdev)) - pitch /= 16; - } - /* r100/r200 divide by 16 */ if (rdev->family < CHIP_R300) flags |= pitch / 16; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2d3655f..393880a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/module.h> #include <drm/drmP.h> #include <drm/radeon_drm.h> @@ -2144,7 +2143,6 @@ void r600_cp_stop(struct radeon_device *rdev) int r600_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; const char *smc_chip_name = "RV770"; @@ -2154,13 +2152,6 @@ int r600_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_R600: chip_name = "R600"; @@ -2272,7 +2263,7 @@ int r600_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -2284,7 +2275,7 @@ int r600_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -2295,7 +2286,7 @@ int r600_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -2307,7 +2298,7 @@ int r600_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -2319,8 +2310,6 @@ int r600_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -3019,7 +3008,7 @@ void r600_uvd_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) { struct radeon_ring *ring = &rdev->ring[fence->ring]; - uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; + uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); radeon_ring_write(ring, fence->seq); @@ -3145,6 +3134,87 @@ int r600_copy_blit(struct radeon_device *rdev, } /** + * r600_copy_cpdma - copy pages using the CP DMA engine + * + * @rdev: radeon_device pointer + * @src_offset: src GPU address + * @dst_offset: dst GPU address + * @num_gpu_pages: number of GPU pages to xfer + * @fence: radeon fence object + * + * Copy GPU paging using the CP DMA engine (r6xx+). + * Used by the radeon ttm implementation to move pages if + * registered as the asic copy callback. + */ +int r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence **fence) +{ + struct radeon_semaphore *sem = NULL; + int ring_index = rdev->asic->copy.blit_ring_index; + struct radeon_ring *ring = &rdev->ring[ring_index]; + u32 size_in_bytes, cur_size_in_bytes, tmp; + int i, num_loops; + int r = 0; + + r = radeon_semaphore_create(rdev, &sem); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + return r; + } + + size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); + num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff); + r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + radeon_semaphore_free(rdev, &sem, NULL); + return r; + } + + if (radeon_fence_need_sync(*fence, ring->idx)) { + radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, + ring->idx); + radeon_fence_note_sync(*fence, ring->idx); + } else { + radeon_semaphore_free(rdev, &sem, NULL); + } + + for (i = 0; i < num_loops; i++) { + cur_size_in_bytes = size_in_bytes; + if (cur_size_in_bytes > 0x1fffff) + cur_size_in_bytes = 0x1fffff; + size_in_bytes -= cur_size_in_bytes; + tmp = upper_32_bits(src_offset) & 0xff; + if (size_in_bytes == 0) + tmp |= PACKET3_CP_DMA_CP_SYNC; + radeon_ring_write(ring, PACKET3(PACKET3_CP_DMA, 4)); + radeon_ring_write(ring, src_offset & 0xffffffff); + radeon_ring_write(ring, tmp); + radeon_ring_write(ring, dst_offset & 0xffffffff); + radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff); + radeon_ring_write(ring, cur_size_in_bytes); + src_offset += cur_size_in_bytes; + dst_offset += cur_size_in_bytes; + } + radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit); + + r = radeon_fence_emit(rdev, fence, ring->idx); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } + + radeon_ring_unlock_commit(rdev, ring); + radeon_semaphore_free(rdev, &sem, *fence); + + return r; +} + +/** * r600_copy_dma - copy pages using the DMA engine * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 76368c0..b88f54b 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -150,6 +150,30 @@ void r600_dpm_print_ps_status(struct radeon_device *rdev, printk("\n"); } +u32 r600_dpm_get_vblank_time(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 line_time_us, vblank_lines; + u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { + line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / + radeon_crtc->hw_mode.clock; + vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - + radeon_crtc->hw_mode.crtc_vdisplay + + (radeon_crtc->v_border * 2); + vblank_time_us = vblank_lines * line_time_us; + break; + } + } + + return vblank_time_us; +} + void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, u32 *p, u32 *u) { diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h index a95ab21..7c822d9 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.h +++ b/drivers/gpu/drm/radeon/r600_dpm.h @@ -129,6 +129,7 @@ void r600_dpm_print_class_info(u32 class, u32 class2); void r600_dpm_print_cap_info(u32 caps); void r600_dpm_print_ps_status(struct radeon_device *rdev, struct radeon_ps *rps); +u32 r600_dpm_get_vblank_time(struct radeon_device *rdev); bool r600_is_uvd_state(u32 class, u32 class2); void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, u32 *p, u32 *u); diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index e73b2a7..f48240b 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -266,6 +266,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod uint32_t offset; ssize_t err; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (!dig->afmt->enabled) return; @@ -448,6 +451,9 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; u32 hdmi = HDMI0_ERROR_ACK; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (enable && dig->afmt->enabled) return; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index f1b3084..8e3fe81 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -602,6 +602,7 @@ #define L2_BUSY (1 << 0) #define WAIT_UNTIL 0x8040 +#define WAIT_CP_DMA_IDLE_bit (1 << 8) #define WAIT_2D_IDLE_bit (1 << 14) #define WAIT_3D_IDLE_bit (1 << 15) #define WAIT_2D_IDLECLEAN_bit (1 << 16) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f51807f..2f08219 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -97,6 +97,7 @@ extern int radeon_msi; extern int radeon_lockup_timeout; extern int radeon_fastfb; extern int radeon_dpm; +extern int radeon_aspm; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -455,6 +456,7 @@ struct radeon_sa_manager { uint64_t gpu_addr; void *cpu_ptr; uint32_t domain; + uint32_t align; }; struct radeon_sa_bo; @@ -783,6 +785,11 @@ struct radeon_mec { /* number of entries in page table */ #define RADEON_VM_PTE_COUNT (1 << RADEON_VM_BLOCK_SIZE) +/* PTBs (Page Table Blocks) need to be aligned to 32K */ +#define RADEON_VM_PTB_ALIGN_SIZE 32768 +#define RADEON_VM_PTB_ALIGN_MASK (RADEON_VM_PTB_ALIGN_SIZE - 1) +#define RADEON_VM_PTB_ALIGN(a) (((a) + RADEON_VM_PTB_ALIGN_MASK) & ~RADEON_VM_PTB_ALIGN_MASK) + struct radeon_vm { struct list_head list; struct list_head va; @@ -1100,6 +1107,7 @@ enum radeon_pm_state_type { POWER_STATE_TYPE_INTERNAL_THERMAL, POWER_STATE_TYPE_INTERNAL_ACPI, POWER_STATE_TYPE_INTERNAL_ULV, + POWER_STATE_TYPE_INTERNAL_3DPERF, }; enum radeon_pm_profile_type { @@ -1334,6 +1342,12 @@ enum radeon_pcie_gen { RADEON_PCIE_GEN_INVALID = 0xffff }; +enum radeon_dpm_forced_level { + RADEON_DPM_FORCED_LEVEL_AUTO = 0, + RADEON_DPM_FORCED_LEVEL_LOW = 1, + RADEON_DPM_FORCED_LEVEL_HIGH = 2, +}; + struct radeon_dpm { struct radeon_ps *ps; /* number of valid power states */ @@ -1373,6 +1387,8 @@ struct radeon_dpm { bool uvd_active; /* thermal handling */ struct radeon_dpm_thermal thermal; + /* forced levels */ + enum radeon_dpm_forced_level forced_level; }; void radeon_dpm_enable_power_state(struct radeon_device *rdev, @@ -1451,6 +1467,8 @@ struct radeon_uvd { struct radeon_bo *vcpu_bo; void *cpu_addr; uint64_t gpu_addr; + void *saved_bo; + unsigned fw_size; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; struct delayed_work idle_work; @@ -1668,6 +1686,8 @@ struct radeon_asic { u32 (*get_mclk)(struct radeon_device *rdev, bool low); void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps); void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m); + int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level); + bool (*vblank_too_short)(struct radeon_device *rdev); } dpm; /* pageflipping */ struct { @@ -2043,7 +2063,6 @@ struct radeon_device { const struct firmware *rlc_fw; /* r6/700 RLC firmware */ const struct firmware *mc_fw; /* NI MC firmware */ const struct firmware *ce_fw; /* SI CE firmware */ - const struct firmware *uvd_fw; /* UVD firmware */ const struct firmware *mec_fw; /* CIK MEC firmware */ const struct firmware *sdma_fw; /* CIK SDMA firmware */ const struct firmware *smc_fw; /* SMC firmware */ @@ -2435,6 +2454,8 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l)) #define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps)) #define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m)) +#define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l)) +#define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index a5b244d..78bec1a 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1026,8 +1026,8 @@ static struct radeon_asic r600_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, @@ -1119,8 +1119,8 @@ static struct radeon_asic rv6xx_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, @@ -1229,8 +1229,8 @@ static struct radeon_asic rs780_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, @@ -1270,6 +1270,7 @@ static struct radeon_asic rs780_asic = { .get_sclk = &rs780_dpm_get_sclk, .get_mclk = &rs780_dpm_get_mclk, .print_power_state = &rs780_dpm_print_power_state, + .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level, }, .pflip = { .pre_page_flip = &rs600_pre_page_flip, @@ -1393,6 +1394,8 @@ static struct radeon_asic rv770_asic = { .get_mclk = &rv770_dpm_get_mclk, .print_power_state = &rv770_dpm_print_power_state, .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, + .force_performance_level = &rv770_dpm_force_performance_level, + .vblank_too_short = &rv770_dpm_vblank_too_short, }, .pflip = { .pre_page_flip = &rs600_pre_page_flip, @@ -1516,6 +1519,8 @@ static struct radeon_asic evergreen_asic = { .get_mclk = &rv770_dpm_get_mclk, .print_power_state = &rv770_dpm_print_power_state, .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, + .force_performance_level = &rv770_dpm_force_performance_level, + .vblank_too_short = &cypress_dpm_vblank_too_short, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, @@ -1639,6 +1644,7 @@ static struct radeon_asic sumo_asic = { .get_mclk = &sumo_dpm_get_mclk, .print_power_state = &sumo_dpm_print_power_state, .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level, + .force_performance_level = &sumo_dpm_force_performance_level, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, @@ -1762,6 +1768,8 @@ static struct radeon_asic btc_asic = { .get_mclk = &btc_dpm_get_mclk, .print_power_state = &rv770_dpm_print_power_state, .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, + .force_performance_level = &rv770_dpm_force_performance_level, + .vblank_too_short = &btc_dpm_vblank_too_short, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, @@ -1937,6 +1945,8 @@ static struct radeon_asic cayman_asic = { .get_mclk = &ni_dpm_get_mclk, .print_power_state = &ni_dpm_print_power_state, .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level, + .force_performance_level = &ni_dpm_force_performance_level, + .vblank_too_short = &ni_dpm_vblank_too_short, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, @@ -2110,6 +2120,7 @@ static struct radeon_asic trinity_asic = { .get_mclk = &trinity_dpm_get_mclk, .print_power_state = &trinity_dpm_print_power_state, .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level, + .force_performance_level = &trinity_dpm_force_performance_level, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, @@ -2283,6 +2294,8 @@ static struct radeon_asic si_asic = { .get_mclk = &ni_dpm_get_mclk, .print_power_state = &ni_dpm_print_power_state, .debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level, + .force_performance_level = &si_dpm_force_performance_level, + .vblank_too_short = &ni_dpm_vblank_too_short, }, .pflip = { .pre_page_flip = &evergreen_pre_page_flip, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 6822c7a..ca18957 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -340,6 +340,9 @@ int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, struct radeon_fence **fence); +int r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, struct radeon_fence **fence); int r600_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, struct radeon_fence **fence); @@ -430,6 +433,8 @@ u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low); u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low); void rs780_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); +void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m); /* uvd */ int r600_uvd_init(struct radeon_device *rdev); @@ -478,6 +483,9 @@ void rv770_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +int rv770_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); +bool rv770_dpm_vblank_too_short(struct radeon_device *rdev); /* * evergreen @@ -542,6 +550,7 @@ void cypress_dpm_disable(struct radeon_device *rdev); int cypress_dpm_set_power_state(struct radeon_device *rdev); void cypress_dpm_display_configuration_changed(struct radeon_device *rdev); void cypress_dpm_fini(struct radeon_device *rdev); +bool cypress_dpm_vblank_too_short(struct radeon_device *rdev); int btc_dpm_init(struct radeon_device *rdev); void btc_dpm_setup_asic(struct radeon_device *rdev); int btc_dpm_enable(struct radeon_device *rdev); @@ -552,6 +561,7 @@ void btc_dpm_post_set_power_state(struct radeon_device *rdev); void btc_dpm_fini(struct radeon_device *rdev); u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low); u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low); +bool btc_dpm_vblank_too_short(struct radeon_device *rdev); int sumo_dpm_init(struct radeon_device *rdev); int sumo_dpm_enable(struct radeon_device *rdev); void sumo_dpm_disable(struct radeon_device *rdev); @@ -567,6 +577,8 @@ void sumo_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +int sumo_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); /* * cayman @@ -615,6 +627,9 @@ void ni_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +int ni_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); +bool ni_dpm_vblank_too_short(struct radeon_device *rdev); int trinity_dpm_init(struct radeon_device *rdev); int trinity_dpm_enable(struct radeon_device *rdev); void trinity_dpm_disable(struct radeon_device *rdev); @@ -630,6 +645,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +int trinity_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); /* DCE6 - SI */ void dce6_bandwidth_update(struct radeon_device *rdev); @@ -679,6 +696,8 @@ void si_dpm_fini(struct radeon_device *rdev); void si_dpm_display_configuration_changed(struct radeon_device *rdev); void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +int si_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); /* DCE8 - CIK */ void dce8_bandwidth_update(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index b1777d1..e3f3e88 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2441,6 +2441,10 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, case ATOM_VIRTUAL_VOLTAGE_ID1: case ATOM_VIRTUAL_VOLTAGE_ID2: case ATOM_VIRTUAL_VOLTAGE_ID3: + case ATOM_VIRTUAL_VOLTAGE_ID4: + case ATOM_VIRTUAL_VOLTAGE_ID5: + case ATOM_VIRTUAL_VOLTAGE_ID6: + case ATOM_VIRTUAL_VOLTAGE_ID7: if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage, &vddc) == 0) @@ -3509,7 +3513,6 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, u8 frev, crev, i; u16 data_offset, size; union vram_info *vram_info; - u8 *p; memset(mem_info, 0, sizeof(struct atom_memory_info)); @@ -3525,13 +3528,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_3.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V3 *vram_module = (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo; - p = (u8 *)vram_info->v1_3.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V3 *)p; if (le16_to_cpu(vram_module->usSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usSize); + vram_module = (ATOM_VRAM_MODULE_V3 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usSize)); } mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0; @@ -3543,13 +3545,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3568,13 +3569,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V7 *vram_module = (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo; - p = (u8 *)vram_info->v2_1.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V7 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V7 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3624,21 +3624,19 @@ int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; - ATOM_MEMORY_TIMING_FORMAT *format; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mclk_range_table->num_entries = (u8) - ((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / + ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / mem_timing_size); - p = (u8 *)vram_module->asMemTiming; + p = (u8 *)&vram_module->asMemTiming[0]; for (i = 0; i < mclk_range_table->num_entries; i++) { - format = (ATOM_MEMORY_TIMING_FORMAT *)p; + ATOM_MEMORY_TIMING_FORMAT *format = (ATOM_MEMORY_TIMING_FORMAT *)p; mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange); p += mem_timing_size; } @@ -3701,17 +3699,21 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, (ATOM_MEMORY_SETTING_DATA_BLOCK *) ((u8 *)reg_block + (2 * sizeof(u16)) + le16_to_cpu(reg_block->usRegIndexTblSize)); + ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) return -EINVAL; - while (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) && - (i < num_entries)) { + while (i < num_entries) { + if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) + break; reg_table->mc_reg_address[i].s1 = - (u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex)); + (u16)(le16_to_cpu(format->usRegIndex)); reg_table->mc_reg_address[i].pre_reg_data = - (u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength); + (u8)(format->ucPreRegDataLength); i++; + format = (ATOM_INIT_REG_INDEX_FORMAT *) + ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); } reg_table->last = i; while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) && diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e5419b3..29876b1 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -167,6 +167,7 @@ int radeon_msi = -1; int radeon_lockup_timeout = 10000; int radeon_fastfb = 0; int radeon_dpm = -1; +int radeon_aspm = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -225,6 +226,9 @@ module_param_named(fastfb, radeon_fastfb, int, 0444); MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(dpm, radeon_dpm, int, 0444); +MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(aspm, radeon_aspm, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index b174674..665ced3 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -230,7 +230,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { - DRM_ERROR("failed to initalise framebuffer %d\n", ret); + DRM_ERROR("failed to initialize framebuffer %d\n", ret); goto out_unref; } diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ddb8f8e..7ddb0ef 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) } else { /* put fence directly behind firmware */ - index = ALIGN(rdev->uvd_fw->size, 8); + index = ALIGN(rdev->uvd.fw_size, 8); rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 43ec4a4..d9d31a3 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -466,7 +466,8 @@ int radeon_vm_manager_init(struct radeon_device *rdev) size += rdev->vm_manager.max_pfn * 8; size *= 2; r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, - RADEON_GPU_PAGE_ALIGN(size), + RADEON_VM_PTB_ALIGN(size), + RADEON_VM_PTB_ALIGN_SIZE, RADEON_GEM_DOMAIN_VRAM); if (r) { dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", @@ -620,10 +621,10 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) } retry: - pd_size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev)); + pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev)); r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->page_directory, pd_size, - RADEON_GPU_PAGE_SIZE, false); + RADEON_VM_PTB_ALIGN_SIZE, false); if (r == -ENOMEM) { r = radeon_vm_evict(rdev, vm); if (r) @@ -952,8 +953,8 @@ static int radeon_vm_update_pdes(struct radeon_device *rdev, retry: r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->page_tables[pt_idx], - RADEON_VM_PTE_COUNT * 8, - RADEON_GPU_PAGE_SIZE, false); + RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8), + RADEON_VM_PTB_ALIGN_SIZE, false); if (r == -ENOMEM) { r = radeon_vm_evict(rdev, vm); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index bcdefd1..081886b 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -260,10 +260,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev) { int r = 0; - INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); - INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); - INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); - spin_lock_init(&rdev->irq.lock); r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { @@ -285,6 +281,11 @@ int radeon_irq_kms_init(struct radeon_device *rdev) rdev->irq.installed = false; return r; } + + INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); + INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); + INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); + DRM_INFO("radeon: irq initialized.\n"); return 0; } @@ -304,8 +305,8 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) rdev->irq.installed = false; if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); + flush_work(&rdev->hotplug_work); } - flush_work(&rdev->hotplug_work); } /** diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b568cb1..8296632 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -335,6 +335,7 @@ struct radeon_crtc { u32 line_time; u32 wm_low; u32 wm_high; + struct drm_display_mode hw_mode; }; struct radeon_encoder_primary_dac { diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 0219d26..2020bf4 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -377,6 +377,7 @@ int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, domain = lobj->alt_domain; goto retry; } + ttm_eu_backoff_reservation(ticket, head); return r; } } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 91519a5..49c82c4 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -174,7 +174,7 @@ static inline void * radeon_sa_bo_cpu_addr(struct radeon_sa_bo *sa_bo) extern int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain); + unsigned size, u32 align, u32 domain); extern void radeon_sa_bo_manager_fini(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager); extern int radeon_sa_bo_manager_start(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index ebbdb47..f374c46 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -468,9 +468,57 @@ fail: return count; } +static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; + + return snprintf(buf, PAGE_SIZE, "%s\n", + (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" : + (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high"); +} + +static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + enum radeon_dpm_forced_level level; + int ret = 0; + + mutex_lock(&rdev->pm.mutex); + if (strncmp("low", buf, strlen("low")) == 0) { + level = RADEON_DPM_FORCED_LEVEL_LOW; + } else if (strncmp("high", buf, strlen("high")) == 0) { + level = RADEON_DPM_FORCED_LEVEL_HIGH; + } else if (strncmp("auto", buf, strlen("auto")) == 0) { + level = RADEON_DPM_FORCED_LEVEL_AUTO; + } else { + mutex_unlock(&rdev->pm.mutex); + count = -EINVAL; + goto fail; + } + if (rdev->asic->dpm.force_performance_level) { + ret = radeon_dpm_force_performance_level(rdev, level); + if (ret) + count = -EINVAL; + } + mutex_unlock(&rdev->pm.mutex); +fail: + return count; +} + static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); +static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, + radeon_get_dpm_forced_performance_level, + radeon_set_dpm_forced_performance_level); static ssize_t radeon_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -585,12 +633,25 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, int i; struct radeon_ps *ps; u32 ui_class; + bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? + true : false; -restart_search: + /* check if the vblank period is too short to adjust the mclk */ + if (single_display && rdev->asic->dpm.vblank_too_short) { + if (radeon_dpm_vblank_too_short(rdev)) + single_display = false; + } + + /* certain older asics have a separare 3D performance state, + * so try that first if the user selected performance + */ + if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) + dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; /* balanced states don't exist at the moment */ if (dpm_state == POWER_STATE_TYPE_BALANCED) dpm_state = POWER_STATE_TYPE_PERFORMANCE; +restart_search: /* Pick the best power state based on current conditions */ for (i = 0; i < rdev->pm.dpm.num_ps; i++) { ps = &rdev->pm.dpm.ps[i]; @@ -600,7 +661,7 @@ restart_search: case POWER_STATE_TYPE_BATTERY: if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (rdev->pm.dpm.new_active_crtc_count < 2) + if (single_display) return ps; } else return ps; @@ -609,7 +670,7 @@ restart_search: case POWER_STATE_TYPE_BALANCED: if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (rdev->pm.dpm.new_active_crtc_count < 2) + if (single_display) return ps; } else return ps; @@ -618,7 +679,7 @@ restart_search: case POWER_STATE_TYPE_PERFORMANCE: if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (rdev->pm.dpm.new_active_crtc_count < 2) + if (single_display) return ps; } else return ps; @@ -657,6 +718,10 @@ restart_search: if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) return ps; break; + case POWER_STATE_TYPE_INTERNAL_3DPERF: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) + return ps; + break; default: break; } @@ -675,6 +740,8 @@ restart_search: dpm_state = POWER_STATE_TYPE_BATTERY; goto restart_search; case POWER_STATE_TYPE_BATTERY: + case POWER_STATE_TYPE_BALANCED: + case POWER_STATE_TYPE_INTERNAL_3DPERF: dpm_state = POWER_STATE_TYPE_PERFORMANCE; goto restart_search; default: @@ -852,7 +919,7 @@ static void radeon_pm_resume_old(struct radeon_device *rdev) { /* set up the default clocks if the MC ucode is loaded */ if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && + (rdev->family <= CHIP_HAINAN) && rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, @@ -896,7 +963,7 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev) if (ret) { DRM_ERROR("radeon: dpm resume failed\n"); if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && + (rdev->family <= CHIP_HAINAN) && rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, @@ -947,7 +1014,7 @@ static int radeon_pm_init_old(struct radeon_device *rdev) radeon_pm_init_profile(rdev); /* set up the default clocks if the MC ucode is loaded */ if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && + (rdev->family <= CHIP_HAINAN) && rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, @@ -1003,8 +1070,8 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) int ret; /* default to performance state */ - rdev->pm.dpm.state = POWER_STATE_TYPE_PERFORMANCE; - rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED; + rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED; rdev->pm.default_sclk = rdev->clock.default_sclk; rdev->pm.default_mclk = rdev->clock.default_mclk; rdev->pm.current_sclk = rdev->clock.default_sclk; @@ -1032,7 +1099,7 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) if (ret) { rdev->pm.dpm_enabled = false; if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && + (rdev->family <= CHIP_HAINAN) && rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, @@ -1055,6 +1122,9 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); if (ret) DRM_ERROR("failed to create device file for dpm state\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); /* XXX: these are noops for dpm but are here for backwards compat */ ret = device_create_file(rdev->dev, &dev_attr_power_profile); if (ret) @@ -1159,6 +1229,7 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); device_remove_file(rdev->dev, &dev_attr_power_dpm_state); + device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); /* XXX backwards compat */ device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); @@ -1188,7 +1259,6 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) if (rdev->pm.num_power_states < 2) return; - INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler); mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 5f1c51a..fb5ea62 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -224,6 +224,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev) } r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, RADEON_IB_POOL_SIZE*64*1024, + RADEON_GPU_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT); if (r) { return r; diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 0abe5a9..f0bac68 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -49,7 +49,7 @@ static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager); int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain) + unsigned size, u32 align, u32 domain) { int i, r; @@ -57,13 +57,14 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, sa_manager->bo = NULL; sa_manager->size = size; sa_manager->domain = domain; + sa_manager->align = align; sa_manager->hole = &sa_manager->olist; INIT_LIST_HEAD(&sa_manager->olist); for (i = 0; i < RADEON_NUM_RINGS; ++i) { INIT_LIST_HEAD(&sa_manager->flist[i]); } - r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, + r = radeon_bo_create(rdev, size, align, true, domain, NULL, &sa_manager->bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); @@ -317,7 +318,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, unsigned tries[RADEON_NUM_RINGS]; int i, r; - BUG_ON(align > RADEON_GPU_PAGE_SIZE); + BUG_ON(align > sa_manager->align); BUG_ON(size > sa_manager->size); *sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 41efcec..414fd14 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -56,20 +56,13 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); int radeon_uvd_init(struct radeon_device *rdev) { - struct platform_device *pdev; + const struct firmware *fw; unsigned long bo_size; const char *fw_name; int i, r; INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); - pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); - r = IS_ERR(pdev); - if (r) { - dev_err(rdev->dev, "radeon_uvd: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_RV710: case CHIP_RV730: @@ -112,17 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev) return -EINVAL; } - r = request_firmware(&rdev->uvd_fw, fw_name, &pdev->dev); + r = request_firmware(&fw, fw_name, rdev->dev); if (r) { dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", fw_name); - platform_device_unregister(pdev); return r; } - platform_device_unregister(pdev); - - bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + + bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); @@ -131,16 +121,35 @@ int radeon_uvd_init(struct radeon_device *rdev) return r; } - r = radeon_uvd_resume(rdev); - if (r) + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); + if (r) { + radeon_bo_unref(&rdev->uvd.vcpu_bo); + dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); return r; + } - memset(rdev->uvd.cpu_addr, 0, bo_size); - memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); + r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, + &rdev->uvd.gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + radeon_bo_unref(&rdev->uvd.vcpu_bo); + dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); + return r; + } - r = radeon_uvd_suspend(rdev); - if (r) + r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); + if (r) { + dev_err(rdev->dev, "(%d) UVD map failed\n", r); return r; + } + + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + + rdev->uvd.fw_size = fw->size; + memset(rdev->uvd.cpu_addr, 0, bo_size); + memcpy(rdev->uvd.cpu_addr, fw->data, fw->size); + + release_firmware(fw); for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { atomic_set(&rdev->uvd.handles[i], 0); @@ -152,71 +161,47 @@ int radeon_uvd_init(struct radeon_device *rdev) void radeon_uvd_fini(struct radeon_device *rdev) { - radeon_uvd_suspend(rdev); - radeon_bo_unref(&rdev->uvd.vcpu_bo); -} - -int radeon_uvd_suspend(struct radeon_device *rdev) -{ int r; if (rdev->uvd.vcpu_bo == NULL) - return 0; + return; r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); if (!r) { radeon_bo_kunmap(rdev->uvd.vcpu_bo); radeon_bo_unpin(rdev->uvd.vcpu_bo); - rdev->uvd.cpu_addr = NULL; - if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) { - radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); - } radeon_bo_unreserve(rdev->uvd.vcpu_bo); - - if (rdev->uvd.cpu_addr) { - radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); - } else { - rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL; - } } - return r; + + radeon_bo_unref(&rdev->uvd.vcpu_bo); } -int radeon_uvd_resume(struct radeon_device *rdev) +int radeon_uvd_suspend(struct radeon_device *rdev) { - int r; + unsigned size; if (rdev->uvd.vcpu_bo == NULL) - return -EINVAL; + return 0; - r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); - if (r) { - radeon_bo_unref(&rdev->uvd.vcpu_bo); - dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); - return r; - } + size = radeon_bo_size(rdev->uvd.vcpu_bo); + rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); + memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size); - /* Have been pin in cpu unmap unpin */ - radeon_bo_kunmap(rdev->uvd.vcpu_bo); - radeon_bo_unpin(rdev->uvd.vcpu_bo); + return 0; +} - r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, - &rdev->uvd.gpu_addr); - if (r) { - radeon_bo_unreserve(rdev->uvd.vcpu_bo); - radeon_bo_unref(&rdev->uvd.vcpu_bo); - dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); - return r; - } +int radeon_uvd_resume(struct radeon_device *rdev) +{ + if (rdev->uvd.vcpu_bo == NULL) + return -EINVAL; - r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); - if (r) { - dev_err(rdev->dev, "(%d) UVD map failed\n", r); - return r; + if (rdev->uvd.saved_bo != NULL) { + unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo); + memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size); + kfree(rdev->uvd.saved_bo); + rdev->uvd.saved_bo = NULL; } - radeon_bo_unreserve(rdev->uvd.vcpu_bo); - return 0; } diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index bef832a..d1a1ce7 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -28,6 +28,7 @@ #include "r600_dpm.h" #include "rs780_dpm.h" #include "atom.h" +#include <linux/seq_file.h> static struct igp_ps *rs780_get_ps(struct radeon_ps *rps) { @@ -961,3 +962,27 @@ u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low) return pi->bootup_uma_clk; } + +void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct igp_ps *ps = rs780_get_ps(rps); + u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK; + u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL); + u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1; + u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 + + ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1; + u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) / + (post_div * ref_div); + + seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + + /* guess based on the current sclk */ + if (sclk < (ps->sclk_low + 500)) + seq_printf(m, "power level 0 sclk: %u vddc_index: %d\n", + ps->sclk_low, ps->min_voltage); + else + seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n", + ps->sclk_high, ps->max_voltage); +} diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h index b1142ed..cfbe9a4 100644 --- a/drivers/gpu/drm/radeon/rs780d.h +++ b/drivers/gpu/drm/radeon/rs780d.h @@ -28,6 +28,7 @@ # define SPLL_SLEEP (1 << 1) # define SPLL_REF_DIV(x) ((x) << 2) # define SPLL_REF_DIV_MASK (7 << 2) +# define SPLL_REF_DIV_SHIFT 2 # define SPLL_FB_DIV(x) ((x) << 5) # define SPLL_FB_DIV_MASK (0xff << 2) # define SPLL_FB_DIV_SHIFT 2 @@ -36,8 +37,10 @@ # define SPLL_PULSENUM_MASK (3 << 14) # define SPLL_SW_HILEN(x) ((x) << 16) # define SPLL_SW_HILEN_MASK (0xf << 16) +# define SPLL_SW_HILEN_SHIFT 16 # define SPLL_SW_LOLEN(x) ((x) << 20) # define SPLL_SW_LOLEN_MASK (0xf << 20) +# define SPLL_SW_LOLEN_SHIFT 20 # define SPLL_DIVEN (1 << 24) # define SPLL_BYPASS_EN (1 << 25) # define SPLL_CHG_STATUS (1 << 29) diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 8303de2..65e33f3 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1763,12 +1763,14 @@ void rv6xx_setup_asic(struct radeon_device *rdev) { r600_enable_acpi_pm(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) - rv6xx_enable_l0s(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) - rv6xx_enable_l1(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) - rv6xx_enable_pll_sleep_in_l1(rdev); + if (radeon_aspm != 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) + rv6xx_enable_l0s(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) + rv6xx_enable_l1(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) + rv6xx_enable_pll_sleep_in_l1(rdev); + } } void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4a62ad2..30ea14e 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 9af464d..2d34792 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -1341,10 +1341,10 @@ static void rv770_program_display_gap(struct radeon_device *rdev) u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); - if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) { + if (rdev->pm.dpm.new_active_crtcs & 1) { tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); - } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) { + } else if (rdev->pm.dpm.new_active_crtcs & 2) { tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); } else { @@ -1471,14 +1471,30 @@ int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev) return 0; } -int rv770_unrestrict_performance_levels_after_switch(struct radeon_device *rdev) +int rv770_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) { - if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK) - return -EINVAL; + PPSMC_Msg msg; + + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK) + return -EINVAL; + msg = PPSMC_MSG_ForceHigh; + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) + return -EINVAL; + msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled); + } else { + if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) + return -EINVAL; + msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled); + } - if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled)) != PPSMC_Result_OK) + if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK) return -EINVAL; + rdev->pm.dpm.forced_level = level; + return 0; } @@ -2047,9 +2063,10 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev) if (pi->dcodt) rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps); rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); - ret = rv770_unrestrict_performance_levels_after_switch(rdev); + + ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { - DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n"); + DRM_ERROR("rv770_dpm_force_performance_level failed\n"); return ret; } @@ -2082,12 +2099,14 @@ void rv770_dpm_setup_asic(struct radeon_device *rdev) rv770_enable_acpi_pm(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) - rv770_enable_l0s(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) - rv770_enable_l1(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) - rv770_enable_pll_sleep_in_l1(rdev); + if (radeon_aspm != 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) + rv770_enable_l0s(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) + rv770_enable_l1(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) + rv770_enable_pll_sleep_in_l1(rdev); + } } void rv770_dpm_display_configuration_changed(struct radeon_device *rdev) @@ -2491,3 +2510,14 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low) else return requested_state->high.mclk; } + +bool rv770_dpm_vblank_too_short(struct radeon_device *rdev) +{ + u32 vblank_time = r600_dpm_get_vblank_time(rdev); + + if (vblank_time < 300) + return true; + else + return false; + +} diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h index f1e1fcf..96b1b2a 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.h +++ b/drivers/gpu/drm/radeon/rv770_dpm.h @@ -262,7 +262,8 @@ void rv770_stop_dpm(struct radeon_device *rdev); void r7xx_stop_smc(struct radeon_device *rdev); void rv770_reset_smio_status(struct radeon_device *rdev); int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev); -int rv770_unrestrict_performance_levels_after_switch(struct radeon_device *rdev); +int rv770_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level); int rv770_halt_smc(struct radeon_device *rdev); int rv770_resume_smc(struct radeon_device *rdev); int rv770_set_sw_state(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 2349067..d325280 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include <drm/drmP.h> @@ -1541,7 +1540,6 @@ static int si_mc_load_microcode(struct radeon_device *rdev) static int si_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; @@ -1551,13 +1549,6 @@ static int si_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_TAHITI: chip_name = "TAHITI"; @@ -1615,7 +1606,7 @@ static int si_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -1627,7 +1618,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -1638,7 +1629,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); - err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->ce_fw->size != ce_req_size) { @@ -1649,7 +1640,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -1660,7 +1651,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -1671,7 +1662,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -1682,8 +1673,6 @@ static int si_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -4401,6 +4390,270 @@ void si_vm_fini(struct radeon_device *rdev) } /** + * si_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (SI). + */ +static void si_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block; + + if (rdev->family == CHIP_TAHITI) { + switch (mc_id) { + case 160: + case 144: + case 96: + case 80: + case 224: + case 208: + case 32: + case 16: + block = "CB"; + break; + case 161: + case 145: + case 97: + case 81: + case 225: + case 209: + case 33: + case 17: + block = "CB_FMASK"; + break; + case 162: + case 146: + case 98: + case 82: + case 226: + case 210: + case 34: + case 18: + block = "CB_CMASK"; + break; + case 163: + case 147: + case 99: + case 83: + case 227: + case 211: + case 35: + case 19: + block = "CB_IMMED"; + break; + case 164: + case 148: + case 100: + case 84: + case 228: + case 212: + case 36: + case 20: + block = "DB"; + break; + case 165: + case 149: + case 101: + case 85: + case 229: + case 213: + case 37: + case 21: + block = "DB_HTILE"; + break; + case 167: + case 151: + case 103: + case 87: + case 231: + case 215: + case 39: + case 23: + block = "DB_STEN"; + break; + case 72: + case 68: + case 64: + case 8: + case 4: + case 0: + case 136: + case 132: + case 128: + case 200: + case 196: + case 192: + block = "TC"; + break; + case 112: + case 48: + block = "CP"; + break; + case 49: + case 177: + case 50: + case 178: + block = "SH"; + break; + case 53: + case 190: + block = "VGT"; + break; + case 117: + block = "IH"; + break; + case 51: + case 115: + block = "RLC"; + break; + case 119: + case 183: + block = "DMA0"; + break; + case 61: + block = "DMA1"; + break; + case 248: + case 120: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + } else { + switch (mc_id) { + case 32: + case 16: + case 96: + case 80: + case 160: + case 144: + case 224: + case 208: + block = "CB"; + break; + case 33: + case 17: + case 97: + case 81: + case 161: + case 145: + case 225: + case 209: + block = "CB_FMASK"; + break; + case 34: + case 18: + case 98: + case 82: + case 162: + case 146: + case 226: + case 210: + block = "CB_CMASK"; + break; + case 35: + case 19: + case 99: + case 83: + case 163: + case 147: + case 227: + case 211: + block = "CB_IMMED"; + break; + case 36: + case 20: + case 100: + case 84: + case 164: + case 148: + case 228: + case 212: + block = "DB"; + break; + case 37: + case 21: + case 101: + case 85: + case 165: + case 149: + case 229: + case 213: + block = "DB_HTILE"; + break; + case 39: + case 23: + case 103: + case 87: + case 167: + case 151: + case 231: + case 215: + block = "DB_STEN"; + break; + case 72: + case 68: + case 8: + case 4: + case 136: + case 132: + case 200: + case 196: + block = "TC"; + break; + case 112: + case 48: + block = "CP"; + break; + case 49: + case 177: + case 50: + case 178: + block = "SH"; + break; + case 53: + block = "VGT"; + break; + case 117: + block = "IH"; + break; + case 51: + case 115: + block = "RLC"; + break; + case 119: + case 183: + block = "DMA0"; + break; + case 61: + block = "DMA1"; + break; + case 248: + case 120: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + } + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + +/** * si_vm_set_page - update the page tables using the CP * * @rdev: radeon_device pointer @@ -5766,6 +6019,7 @@ int si_irq_process(struct radeon_device *rdev) u32 ring_index; bool queue_hotplug = false; bool queue_thermal = false; + u32 status, addr; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -6001,11 +6255,14 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + si_vm_decode_fault(rdev, status, addr); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; @@ -6796,6 +7053,9 @@ static void si_program_aspm(struct radeon_device *rdev) bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; bool disable_clkreq = false; + if (radeon_aspm == 0) + return; + if (!(rdev->flags & RADEON_IS_PCIE)) return; diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index a7e97cd..73aaa2e 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2906,7 +2906,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, u16 vddc, vddci; int i; - if (rdev->pm.dpm.new_active_crtc_count > 1) + if ((rdev->pm.dpm.new_active_crtc_count > 1) || + ni_dpm_vblank_too_short(rdev)) disable_mclk_switching = true; else disable_mclk_switching = false; @@ -3231,16 +3232,38 @@ static int si_restrict_performance_levels_before_switch(struct radeon_device *rd 0 : -EINVAL; } -#if 0 -static int si_unrestrict_performance_levels_after_switch(struct radeon_device *rdev) +int si_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) { - if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) - return -EINVAL; + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct ni_ps *ps = ni_get_ps(rps); + u32 levels; - return (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) == PPSMC_Result_OK) ? - 0 : -EINVAL; + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK) + return -EINVAL; + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + levels = ps->performance_level_count - 1; + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) + return -EINVAL; + } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + return -EINVAL; + } + + rdev->pm.dpm.forced_level = level; + + return 0; } -#endif static int si_set_boot_state(struct radeon_device *rdev) { @@ -5992,11 +6015,13 @@ int si_dpm_set_power_state(struct radeon_device *rdev) #if 0 /* XXX */ - ret = si_unrestrict_performance_levels_after_switch(rdev); + ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { - DRM_ERROR("si_unrestrict_performance_levels_after_switch failed\n"); + DRM_ERROR("si_dpm_force_performance_level failed\n"); return ret; } +#else + rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; #endif return 0; diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 12a20eb..2c8da27 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -367,6 +367,20 @@ #define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC #define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 1: pde0 + * bit 2: valid + * bit 3: read + * bit 4: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0xf << 25) +#define FAULT_VMID_SHIFT 25 #define VM_INVALIDATE_REQUEST 0x1478 #define VM_INVALIDATE_RESPONSE 0x147c diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index dc59906..c0a8503 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1319,6 +1319,8 @@ int sumo_dpm_set_power_state(struct radeon_device *rdev) if (pi->enable_dpm) sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); + rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; + return 0; } @@ -1730,7 +1732,13 @@ int sumo_dpm_init(struct radeon_device *rdev) pi->enable_sclk_ds = true; pi->enable_dynamic_m3_arbiter = false; pi->enable_dynamic_patch_ps = true; - pi->enable_gfx_power_gating = true; + /* Some PALM chips don't seem to properly ungate gfx when UVD is in use; + * for now just disable gfx PG. + */ + if (rdev->family == CHIP_PALM) + pi->enable_gfx_power_gating = false; + else + pi->enable_gfx_power_gating = true; pi->enable_gfx_clock_gating = true; pi->enable_mg_clock_gating = true; pi->enable_auto_thermal_throttling = true; @@ -1830,3 +1838,51 @@ u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low) return pi->sys_info.bootup_uma_clk; } + +int sumo_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) +{ + struct sumo_power_info *pi = sumo_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; + struct sumo_ps *ps = sumo_get_ps(rps); + int i; + + if (ps->num_levels <= 1) + return 0; + + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, false); + sumo_power_level_enable(rdev, ps->num_levels - 1, true); + sumo_set_forced_level(rdev, ps->num_levels - 1); + sumo_set_forced_mode_enabled(rdev); + for (i = 0; i < ps->num_levels - 1; i++) { + sumo_power_level_enable(rdev, i, false); + } + sumo_set_forced_mode(rdev, false); + sumo_set_forced_mode_enabled(rdev); + sumo_set_forced_mode(rdev, false); + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, false); + sumo_power_level_enable(rdev, 0, true); + sumo_set_forced_level(rdev, 0); + sumo_set_forced_mode_enabled(rdev); + for (i = 1; i < ps->num_levels; i++) { + sumo_power_level_enable(rdev, i, false); + } + sumo_set_forced_mode(rdev, false); + sumo_set_forced_mode_enabled(rdev); + sumo_set_forced_mode(rdev, false); + } else { + for (i = 0; i < ps->num_levels; i++) { + sumo_power_level_enable(rdev, i, true); + } + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, true); + } + + rdev->pm.dpm.forced_level = level; + + return 0; +} diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 8a32bcc..a1eb5f5 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1158,6 +1158,37 @@ static void trinity_setup_nbp_sim(struct radeon_device *rdev, } } +int trinity_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) +{ + struct trinity_power_info *pi = trinity_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; + struct trinity_ps *ps = trinity_get_ps(rps); + int i, ret; + + if (ps->num_levels <= 1) + return 0; + + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + /* not supported by the hw */ + return -EINVAL; + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1); + if (ret) + return ret; + } else { + for (i = 0; i < ps->num_levels; i++) { + ret = trinity_dpm_n_levels_disabled(rdev, 0); + if (ret) + return ret; + } + } + + rdev->pm.dpm.forced_level = level; + + return 0; +} + int trinity_dpm_pre_set_power_state(struct radeon_device *rdev) { struct trinity_power_info *pi = trinity_get_pi(rdev); @@ -1190,6 +1221,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev) trinity_force_level_0(rdev); trinity_unforce_levels(rdev); trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); + rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; } trinity_release_mutex(rdev); diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h index c621b84..e82df07 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.h +++ b/drivers/gpu/drm/radeon/trinity_dpm.h @@ -121,6 +121,7 @@ struct trinity_power_info { int trinity_dpm_config(struct radeon_device *rdev, bool enable); int trinity_uvd_dpm_config(struct radeon_device *rdev); int trinity_dpm_force_state(struct radeon_device *rdev, u32 n); +int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n); int trinity_dpm_no_forced_level(struct radeon_device *rdev); int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev, bool enable); diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c index 85f86a2..a42d89f 100644 --- a/drivers/gpu/drm/radeon/trinity_smc.c +++ b/drivers/gpu/drm/radeon/trinity_smc.c @@ -73,6 +73,13 @@ int trinity_dpm_force_state(struct radeon_device *rdev, u32 n) return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState); } +int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n) +{ + WREG32_SMC(SMU_SCRATCH0, n); + + return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_N_LevelsDisabled); +} + int trinity_uvd_dpm_config(struct radeon_device *rdev) { return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 003b34e..dc0fe09 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -249,9 +249,14 @@ static struct drm_driver rcar_du_driver = { .gem_vm_ops = &drm_gem_cma_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = drm_gem_cma_dmabuf_import, - .gem_prime_export = drm_gem_cma_dmabuf_export, - .dumb_create = drm_gem_cma_dumb_create, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .dumb_create = rcar_du_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_cma_dumb_destroy, .fops = &rcar_du_fops, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 9c63f39..d30c2e2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -138,11 +138,25 @@ void rcar_du_encoder_mode_commit(struct drm_encoder *encoder) * Frame buffer */ +int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + unsigned int align; + + /* The pitch must be aligned to a 16 pixels boundary. */ + align = 16 * args->bpp / 8; + args->pitch = roundup(max(args->pitch, min_pitch), align); + + return drm_gem_cma_dumb_create(file, dev, args); +} + static struct drm_framebuffer * rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { const struct rcar_du_format_info *format; + unsigned int align; format = rcar_du_format_info(mode_cmd->pixel_format); if (format == NULL) { @@ -151,7 +165,10 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-EINVAL); } - if (mode_cmd->pitches[0] & 15 || mode_cmd->pitches[0] >= 8192) { + align = 16 * format->bpp / 8; + + if (mode_cmd->pitches[0] & (align - 1) || + mode_cmd->pitches[0] >= 8192) { dev_dbg(dev->dev, "invalid pitch value %u\n", mode_cmd->pitches[0]); return ERR_PTR(-EINVAL); @@ -191,8 +208,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) if (ret < 0) return ret; - for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) - rcar_du_crtc_create(rcdu, i); + for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) { + ret = rcar_du_crtc_create(rcdu, i); + if (ret < 0) + return ret; + } rcdu->used_crtcs = 0; rcdu->num_crtcs = i; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h index e4d8db0..dba4722 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h @@ -56,4 +56,7 @@ void rcar_du_encoder_mode_commit(struct drm_encoder *encoder); int rcar_du_modeset_init(struct rcar_du_device *rcdu); +int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); + #endif /* __RCAR_DU_KMS_H__ */ diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index edc1018..5f83f9a 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -276,8 +276,13 @@ static struct drm_driver shmob_drm_driver = { .gem_vm_ops = &drm_gem_cma_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = drm_gem_cma_dmabuf_import, - .gem_prime_export = drm_gem_cma_dmabuf_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_cma_dumb_destroy, |