mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 21:21:47 +00:00
drm/msm: fix IOMMU cleanup for -EPROBE_DEFER
If probe fails after IOMMU is attached, we need to detach in order to clean up properly. Before this change, IOMMU faults would occur if the probe failed (-EPROBE_DEFER). Signed-off-by: Stephane Viau <sviau@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
parent
cf3198c205
commit
87e956e9be
@ -20,6 +20,10 @@
|
|||||||
#include "msm_mmu.h"
|
#include "msm_mmu.h"
|
||||||
#include "mdp5_kms.h"
|
#include "mdp5_kms.h"
|
||||||
|
|
||||||
|
static const char *iommu_ports[] = {
|
||||||
|
"mdp_0",
|
||||||
|
};
|
||||||
|
|
||||||
static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
|
static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
|
||||||
|
|
||||||
static int mdp5_hw_init(struct msm_kms *kms)
|
static int mdp5_hw_init(struct msm_kms *kms)
|
||||||
@ -104,6 +108,12 @@ static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
|
|||||||
static void mdp5_destroy(struct msm_kms *kms)
|
static void mdp5_destroy(struct msm_kms *kms)
|
||||||
{
|
{
|
||||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
||||||
|
struct msm_mmu *mmu = mdp5_kms->mmu;
|
||||||
|
|
||||||
|
if (mmu) {
|
||||||
|
mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
|
||||||
|
mmu->funcs->destroy(mmu);
|
||||||
|
}
|
||||||
kfree(mdp5_kms);
|
kfree(mdp5_kms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,10 +226,6 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *iommu_ports[] = {
|
|
||||||
"mdp_0",
|
|
||||||
};
|
|
||||||
|
|
||||||
static int get_clk(struct platform_device *pdev, struct clk **clkp,
|
static int get_clk(struct platform_device *pdev, struct clk **clkp,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
@ -317,17 +323,23 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
|||||||
mmu = msm_iommu_new(dev, config->iommu);
|
mmu = msm_iommu_new(dev, config->iommu);
|
||||||
if (IS_ERR(mmu)) {
|
if (IS_ERR(mmu)) {
|
||||||
ret = PTR_ERR(mmu);
|
ret = PTR_ERR(mmu);
|
||||||
|
dev_err(dev->dev, "failed to init iommu: %d\n", ret);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mmu->funcs->attach(mmu, iommu_ports,
|
ret = mmu->funcs->attach(mmu, iommu_ports,
|
||||||
ARRAY_SIZE(iommu_ports));
|
ARRAY_SIZE(iommu_ports));
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
dev_err(dev->dev, "failed to attach iommu: %d\n", ret);
|
||||||
|
mmu->funcs->destroy(mmu);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dev_info(dev->dev, "no iommu, fallback to phys "
|
dev_info(dev->dev, "no iommu, fallback to phys "
|
||||||
"contig buffers for scanout\n");
|
"contig buffers for scanout\n");
|
||||||
mmu = NULL;
|
mmu = NULL;
|
||||||
}
|
}
|
||||||
|
mdp5_kms->mmu = mmu;
|
||||||
|
|
||||||
mdp5_kms->id = msm_register_mmu(dev, mmu);
|
mdp5_kms->id = msm_register_mmu(dev, mmu);
|
||||||
if (mdp5_kms->id < 0) {
|
if (mdp5_kms->id < 0) {
|
||||||
|
@ -33,6 +33,7 @@ struct mdp5_kms {
|
|||||||
|
|
||||||
/* mapper-id used to request GEM buffer mapped for scanout: */
|
/* mapper-id used to request GEM buffer mapped for scanout: */
|
||||||
int id;
|
int id;
|
||||||
|
struct msm_mmu *mmu;
|
||||||
|
|
||||||
/* for tracking smp allocation amongst pipes: */
|
/* for tracking smp allocation amongst pipes: */
|
||||||
mdp5_smp_state_t smp_state;
|
mdp5_smp_state_t smp_state;
|
||||||
|
@ -278,6 +278,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
|
|||||||
uint32_t *iova)
|
uint32_t *iova)
|
||||||
{
|
{
|
||||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||||
|
struct drm_device *dev = obj->dev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!msm_obj->domain[id].iova) {
|
if (!msm_obj->domain[id].iova) {
|
||||||
@ -285,6 +286,11 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
|
|||||||
struct msm_mmu *mmu = priv->mmus[id];
|
struct msm_mmu *mmu = priv->mmus[id];
|
||||||
struct page **pages = get_pages(obj);
|
struct page **pages = get_pages(obj);
|
||||||
|
|
||||||
|
if (!mmu) {
|
||||||
|
dev_err(dev->dev, "null MMU pointer\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ERR(pages))
|
if (IS_ERR(pages))
|
||||||
return PTR_ERR(pages);
|
return PTR_ERR(pages);
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
|
|||||||
unsigned long iova, int flags, void *arg)
|
unsigned long iova, int flags, void *arg)
|
||||||
{
|
{
|
||||||
DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
|
DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
|
||||||
return 0;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
|
static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
|
||||||
@ -40,8 +40,10 @@ static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
|
|||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
struct device *msm_iommu_get_ctx(const char *ctx_name);
|
struct device *msm_iommu_get_ctx(const char *ctx_name);
|
||||||
struct device *ctx = msm_iommu_get_ctx(names[i]);
|
struct device *ctx = msm_iommu_get_ctx(names[i]);
|
||||||
if (IS_ERR_OR_NULL(ctx))
|
if (IS_ERR_OR_NULL(ctx)) {
|
||||||
|
dev_warn(dev->dev, "couldn't get %s context", names[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
ret = iommu_attach_device(iommu->domain, ctx);
|
ret = iommu_attach_device(iommu->domain, ctx);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
|
dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
|
||||||
@ -52,6 +54,20 @@ static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void msm_iommu_detach(struct msm_mmu *mmu, const char **names, int cnt)
|
||||||
|
{
|
||||||
|
struct msm_iommu *iommu = to_msm_iommu(mmu);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
struct device *msm_iommu_get_ctx(const char *ctx_name);
|
||||||
|
struct device *ctx = msm_iommu_get_ctx(names[i]);
|
||||||
|
if (IS_ERR_OR_NULL(ctx))
|
||||||
|
continue;
|
||||||
|
iommu_detach_device(iommu->domain, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
|
static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
|
||||||
struct sg_table *sgt, unsigned len, int prot)
|
struct sg_table *sgt, unsigned len, int prot)
|
||||||
{
|
{
|
||||||
@ -127,6 +143,7 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
|
|||||||
|
|
||||||
static const struct msm_mmu_funcs funcs = {
|
static const struct msm_mmu_funcs funcs = {
|
||||||
.attach = msm_iommu_attach,
|
.attach = msm_iommu_attach,
|
||||||
|
.detach = msm_iommu_detach,
|
||||||
.map = msm_iommu_map,
|
.map = msm_iommu_map,
|
||||||
.unmap = msm_iommu_unmap,
|
.unmap = msm_iommu_unmap,
|
||||||
.destroy = msm_iommu_destroy,
|
.destroy = msm_iommu_destroy,
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
struct msm_mmu_funcs {
|
struct msm_mmu_funcs {
|
||||||
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
|
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
|
||||||
|
void (*detach)(struct msm_mmu *mmu, const char **names, int cnt);
|
||||||
int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
|
int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
|
||||||
unsigned len, int prot);
|
unsigned len, int prot);
|
||||||
int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
|
int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
|
||||||
|
Loading…
Reference in New Issue
Block a user