msm: kgsl: Fixup the GMU probe

Clean up the GMU probe to use standard functions and proper reference to
make it more defer tolerant.

Change-Id: Ic0dedbad7c561e24c07053ea3b19ef62e34621cb
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
Jordan Crouse 2019-11-07 10:08:38 -07:00
commit 8152ccc95e
2 changed files with 80 additions and 126 deletions

View file

@ -25,7 +25,7 @@
struct gmu_iommu_context {
const char *name;
struct device *dev;
struct platform_device *pdev;
struct iommu_domain *domain;
};
@ -277,48 +277,57 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu,
}
static int gmu_iommu_cb_probe(struct gmu_device *gmu,
struct gmu_iommu_context *ctx,
struct device_node *node)
const char *name, struct gmu_iommu_context *ctx,
struct device_node *parent, iommu_fault_handler_t handler)
{
struct platform_device *pdev = of_find_device_by_node(node);
struct device *dev;
struct device_node *node = of_get_child_by_name(parent, name);
struct platform_device *pdev;
int ret;
dev = &pdev->dev;
of_dma_configure(dev, node, true);
if (!node)
return -ENODEV;
ctx->dev = dev;
pdev = of_find_device_by_node(node);
of_dma_configure(&pdev->dev, node, true);
of_node_put(node);
ctx->pdev = pdev;
ctx->domain = iommu_domain_alloc(&platform_bus_type);
if (ctx->domain == NULL) {
dev_err(&gmu->pdev->dev, "gmu iommu fail to alloc %s domain\n",
ctx->name);
platform_device_put(pdev);
return -ENODEV;
}
ret = iommu_attach_device(ctx->domain, dev);
if (ret) {
dev_err(&gmu->pdev->dev, "gmu iommu fail to attach %s device\n",
ctx->name);
iommu_domain_free(ctx->domain);
ret = iommu_attach_device(ctx->domain, &pdev->dev);
if (!ret) {
iommu_set_fault_handler(ctx->domain, handler, ctx);
return 0;
}
dev_err(&gmu->pdev->dev,
"gmu iommu fail to attach %s device\n", ctx->name);
iommu_domain_free(ctx->domain);
ctx->domain = NULL;
platform_device_put(pdev);
return ret;
}
static struct {
const char *compatible;
int index;
iommu_fault_handler_t hdlr;
} cbs[] = {
{ "qcom,smmu-gmu-user-cb",
GMU_CONTEXT_USER,
gmu_user_fault_handler,
},
{ "qcom,smmu-gmu-kernel-cb",
GMU_CONTEXT_KERNEL,
gmu_kernel_fault_handler,
},
};
static void gmu_iommu_cb_close(struct gmu_iommu_context *ctx)
{
if (!ctx->domain)
return;
iommu_detach_device(ctx->domain, &ctx->pdev->dev);
iommu_domain_free(ctx->domain);
platform_device_put(ctx->pdev);
memset(ctx, 0, sizeof(*ctx));
}
/*
* gmu_iommu_init() - probe IOMMU context banks used by GMU
@ -328,34 +337,17 @@ static struct {
*/
static int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
{
struct device_node *child;
struct gmu_iommu_context *ctx = NULL;
int ret, i;
int ret;
of_platform_populate(node, NULL, NULL, &gmu->pdev->dev);
devm_of_platform_populate(&gmu->pdev->dev);
for (i = 0; i < ARRAY_SIZE(cbs); i++) {
child = of_find_compatible_node(node, NULL, cbs[i].compatible);
if (child) {
ctx = &gmu_ctx[cbs[i].index];
ret = gmu_iommu_cb_probe(gmu, ctx, child);
if (ret)
return ret;
iommu_set_fault_handler(ctx->domain,
cbs[i].hdlr, ctx);
}
}
ret = gmu_iommu_cb_probe(gmu, "gmu_user",
&gmu_ctx[GMU_CONTEXT_USER], node, gmu_user_fault_handler);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(gmu_ctx); i++) {
if (gmu_ctx[i].domain == NULL) {
dev_err(&gmu->pdev->dev,
"Missing GMU %s context bank node\n",
gmu_ctx[i].name);
return -EINVAL;
}
}
return 0;
return gmu_iommu_cb_probe(gmu, "gmu_kernel",
&gmu_ctx[GMU_CONTEXT_KERNEL], node, gmu_kernel_fault_handler);
}
/*
@ -394,14 +386,8 @@ static void gmu_memory_close(struct gmu_device *gmu)
clear_bit(i, &gmu->kmem_bitmap);
}
for (i = 0; i < ARRAY_SIZE(gmu_ctx); i++) {
ctx = &gmu_ctx[i];
if (ctx->domain) {
iommu_detach_device(ctx->domain, ctx->dev);
iommu_domain_free(ctx->domain);
}
}
gmu_iommu_cb_close(&gmu_ctx[GMU_CONTEXT_USER]);
gmu_iommu_cb_close(&gmu_ctx[GMU_CONTEXT_KERNEL]);
}
static enum gmu_mem_type gmu_get_blk_memtype(struct gmu_device *gmu,
@ -1061,60 +1047,44 @@ static int gmu_reg_probe(struct kgsl_device *device)
res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
"kgsl_gmu_reg");
if (res == NULL) {
dev_err(&gmu->pdev->dev,
"platform_get_resource kgsl_gmu_reg failed\n");
return -EINVAL;
}
if (res->start == 0 || resource_size(res) == 0) {
dev_err(&gmu->pdev->dev,
"dev %d kgsl_gmu_reg invalid register region\n",
gmu->pdev->dev.id);
return -EINVAL;
}
gmu->reg_phys = res->start;
gmu->reg_len = resource_size(res);
device->gmu_core.reg_virt = devm_ioremap(&gmu->pdev->dev,
res->start, resource_size(res));
if (device->gmu_core.reg_virt == NULL) {
dev_err(&gmu->pdev->dev, "kgsl_gmu_reg ioremap failed\n");
if (!res) {
dev_err(&gmu->pdev->dev, "The GMU register region isn't defined\n");
return -ENODEV;
}
device->gmu_core.gmu2gpu_offset = (res->start - device->reg_phys) >> 2;
device->gmu_core.reg_len = resource_size(res);
/*
* We can't use devm_ioremap_resource here because we purposely double
* map the gpu_cc registers for debugging purposes
*/
device->gmu_core.reg_virt = devm_ioremap(&gmu->pdev->dev, res->start,
resource_size(res));
if (!device->gmu_core.reg_virt) {
dev_err(&gmu->pdev->dev, "Unable to map the GMU registers\n");
return -ENOMEM;
}
return 0;
}
static int gmu_regulators_probe(struct gmu_device *gmu,
struct device_node *node)
struct platform_device *pdev)
{
const char *name;
struct property *prop;
struct device *dev = &gmu->pdev->dev;
int ret = 0;
gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx");
if (IS_ERR(gmu->cx_gdsc)) {
if (PTR_ERR(gmu->cx_gdsc) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Couldn't get the vddcx gdsc\n");
return PTR_ERR(gmu->cx_gdsc);
}
of_property_for_each_string(node, "regulator-names", prop, name) {
if (!strcmp(name, "vddcx")) {
gmu->cx_gdsc = devm_regulator_get(dev, name);
if (IS_ERR(gmu->cx_gdsc)) {
ret = PTR_ERR(gmu->cx_gdsc);
dev_err(dev, "dt: GMU couldn't get CX gdsc\n");
gmu->cx_gdsc = NULL;
return ret;
}
} else if (!strcmp(name, "vdd")) {
gmu->gx_gdsc = devm_regulator_get(dev, name);
if (IS_ERR(gmu->gx_gdsc)) {
ret = PTR_ERR(gmu->gx_gdsc);
dev_err(dev, "dt: GMU couldn't get GX gdsc\n");
gmu->gx_gdsc = NULL;
return ret;
}
} else {
dev_err(dev, "dt: Unknown GMU regulator: %s\n", name);
return -ENODEV;
}
gmu->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(gmu->gx_gdsc)) {
if (PTR_ERR(gmu->gx_gdsc) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Couldn't get the vdd gdsc\n");
return PTR_ERR(gmu->gx_gdsc);
}
return 0;
@ -1321,7 +1291,7 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
gmu->pdev = pdev;
device->gmu_core.ptr = (void *)gmu;
device->gmu_core.ptr = gmu;
hfi = &gmu->hfi;
gmu->load_mode = TCM_BOOT;
@ -1330,11 +1300,11 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
set_dma_ops(&gmu->pdev->dev, NULL);
/* Set up GMU regulators */
ret = gmu_regulators_probe(gmu, pdev->dev.of_node);
ret = gmu_regulators_probe(gmu, pdev);
if (ret)
return ret;
ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
ret = devm_clk_bulk_get_all(&pdev->dev, &gmu->clks);
if (ret < 0)
return ret;
@ -1343,8 +1313,9 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
/* Get a pointer to the GMU clock */
gmu->gmu_clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, "gmu_clk");
if (!gmu->gmu_clk) {
dev_err(&gmu->pdev->dev, "Couldn't get gmu_clk\n");
return -ENODEV;
dev_err(&pdev->dev, "Couldn't get gmu_clk\n");
ret = -ENODEV;
goto error;
}
/* Set up GMU IOMMU and shared memory with GMU */
@ -1366,10 +1337,6 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
if (ret)
goto error;
device->gmu_core.gmu2gpu_offset =
(gmu->reg_phys - device->reg_phys) >> 2;
device->gmu_core.reg_len = gmu->reg_len;
/* Initialize HFI and GMU interrupts */
hfi->hfi_interrupt_num = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq",
hfi_irq_handler, device);
@ -1474,9 +1441,6 @@ static int gmu_enable_gdsc(struct gmu_device *gmu)
{
int ret;
if (IS_ERR_OR_NULL(gmu->cx_gdsc))
return 0;
ret = regulator_enable(gmu->cx_gdsc);
if (ret)
dev_err(&gmu->pdev->dev,
@ -1738,14 +1702,8 @@ static void gmu_remove(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
struct kgsl_hfi *hfi;
if (gmu == NULL || gmu->pdev == NULL)
return;
hfi = &gmu->hfi;
tasklet_kill(&hfi->tasklet);
tasklet_kill(&gmu->hfi.tasklet);
gmu_stop(device);

View file

@ -141,8 +141,6 @@ struct icc_path;
/**
* struct gmu_device - GMU device structure
* @ver: GMU Version information
* @reg_phys: GMU CSR physical address
* @reg_len: GMU CSR range
* @gmu_interrupt_num: GMU interrupt number
* @fw_image: GMU FW image
* @hfi_mem: pointer to HFI shared memory
@ -174,8 +172,6 @@ struct gmu_device {
u32 hfi;
} ver;
struct platform_device *pdev;
unsigned long reg_phys;
unsigned int reg_len;
int gmu_interrupt_num;
const struct firmware *fw_image;
struct gmu_memdesc *hfi_mem;