From 9a0a010c8e9699ff3727022b85403c41dd74932b Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Mon, 30 Jan 2017 23:07:08 -0800 Subject: [PATCH] drm/msm: add SDE IRQ domain before creating DRM objects Currently all connectors list SDE as their parent interrupt controller. With commit (), the SDE IRQ domains get added after DRM init functions of the connectors. This is incorrect as the irq request calls of the connectors shall fail if the domain of the parent is not added yet. Fix this by re-ordering the sde_kms_int() function to reflect the correct order and remove the IRQ domain addition from irq_preinstall calls as that will be very late for the connectors. Change-Id: Ie1364840e2f018361e54470516d48c3facf59272 Signed-off-by: Abhinav Kumar --- drivers/gpu/drm/msm/sde/sde_core_irq.c | 95 +++++++++++++++++++++++++- drivers/gpu/drm/msm/sde/sde_core_irq.h | 16 ++++- drivers/gpu/drm/msm/sde/sde_irq.c | 80 +--------------------- drivers/gpu/drm/msm/sde/sde_kms.c | 24 ++++--- 4 files changed, 125 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c index b2853e874d92..dbfc2dd11a17 100644 --- a/drivers/gpu/drm/msm/sde/sde_core_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -432,6 +432,99 @@ void sde_core_irq_uninstall(struct sde_kms *sde_kms) sde_kms->irq_obj.total_irqs = 0; } +static void sde_hw_irq_mask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + smp_mb__after_atomic(); +} + +static void sde_hw_irq_unmask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + smp_mb__after_atomic(); +} + +static struct irq_chip sde_hw_irq_chip = { + .name = "sde", + .irq_mask = sde_hw_irq_mask, + .irq_unmask = sde_hw_irq_unmask, +}; + +static int sde_hw_irqdomain_map(struct irq_domain *domain, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct sde_kms *sde_kms; + int rc; + + if (!domain || !domain->host_data) { + SDE_ERROR("invalid parameters domain %d\n", domain != 0); + return -EINVAL; + } + sde_kms = domain->host_data; + + irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); + rc = irq_set_chip_data(irq, sde_kms); + + return rc; +} + +static struct irq_domain_ops sde_hw_irqdomain_ops = { + .map = sde_hw_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + +int sde_core_irq_domain_add(struct sde_kms *sde_kms) +{ + struct device *dev; + struct irq_domain *domain; + + if (!sde_kms->dev || !sde_kms->dev->dev) { + pr_err("invalid device handles\n"); + return -EINVAL; + } + + dev = sde_kms->dev->dev; + + domain = irq_domain_add_linear(dev->of_node, 32, + &sde_hw_irqdomain_ops, sde_kms); + if (!domain) { + pr_err("failed to add irq_domain\n"); + return -EINVAL; + } + + sde_kms->irq_controller.enabled_mask = 0; + sde_kms->irq_controller.domain = domain; + + return 0; +} + +int sde_core_irq_domain_fini(struct sde_kms *sde_kms) +{ + if (sde_kms->irq_controller.domain) { + irq_domain_remove(sde_kms->irq_controller.domain); + sde_kms->irq_controller.domain = NULL; + } + return 0; +} + irqreturn_t sde_core_irq(struct sde_kms *sde_kms) { /* diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h index 92642e73daa8..ee1b9bd1d32b 100644 --- a/drivers/gpu/drm/msm/sde/sde_core_irq.h +++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,20 @@ int sde_core_irq_postinstall(struct sde_kms *sde_kms); */ void sde_core_irq_uninstall(struct sde_kms *sde_kms); +/** + * sde_core_irq_domain_add - Add core IRQ domain for SDE + * @sde_kms: SDE handle + * @return: none + */ +int sde_core_irq_domain_add(struct sde_kms *sde_kms); + +/** + * sde_core_irq_domain_fini - uninstall core IRQ domain + * @sde_kms: SDE handle + * @return: 0 if success; error code otherwise + */ +int sde_core_irq_domain_fini(struct sde_kms *sde_kms); + /** * sde_core_irq - core IRQ handler * @sde_kms: SDE handle diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index 909d6df38260..eeb7a0002eab 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -49,86 +49,14 @@ irqreturn_t sde_irq(struct msm_kms *kms) return IRQ_HANDLED; } -static void sde_hw_irq_mask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms; - - if (!irqd || !irq_data_get_irq_chip_data(irqd)) { - SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); - return; - } - sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); - smp_mb__after_atomic(); -} - -static void sde_hw_irq_unmask(struct irq_data *irqd) -{ - struct sde_kms *sde_kms; - - if (!irqd || !irq_data_get_irq_chip_data(irqd)) { - SDE_ERROR("invalid parameters irqd %d\n", irqd != 0); - return; - } - sde_kms = irq_data_get_irq_chip_data(irqd); - - smp_mb__before_atomic(); - set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); - smp_mb__after_atomic(); -} - -static struct irq_chip sde_hw_irq_chip = { - .name = "sde", - .irq_mask = sde_hw_irq_mask, - .irq_unmask = sde_hw_irq_unmask, -}; - -static int sde_hw_irqdomain_map(struct irq_domain *domain, - unsigned int irq, irq_hw_number_t hwirq) -{ - struct sde_kms *sde_kms; - int rc; - - if (!domain || !domain->host_data) { - SDE_ERROR("invalid parameters domain %d\n", domain != 0); - return -EINVAL; - } - sde_kms = domain->host_data; - - irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); - rc = irq_set_chip_data(irq, sde_kms); - - return rc; -} - -static struct irq_domain_ops sde_hw_irqdomain_ops = { - .map = sde_hw_irqdomain_map, - .xlate = irq_domain_xlate_onecell, -}; - void sde_irq_preinstall(struct msm_kms *kms) { struct sde_kms *sde_kms = to_sde_kms(kms); - struct device *dev; - struct irq_domain *domain; if (!sde_kms->dev || !sde_kms->dev->dev) { pr_err("invalid device handles\n"); return; } - dev = sde_kms->dev->dev; - - domain = irq_domain_add_linear(dev->of_node, 32, - &sde_hw_irqdomain_ops, sde_kms); - if (!domain) { - pr_err("failed to add irq_domain\n"); - return; - } - - sde_kms->irq_controller.enabled_mask = 0; - sde_kms->irq_controller.domain = domain; sde_core_irq_preinstall(sde_kms); } @@ -158,9 +86,5 @@ void sde_irq_uninstall(struct msm_kms *kms) } sde_core_irq_uninstall(sde_kms); - - if (sde_kms->irq_controller.domain) { - irq_domain_remove(sde_kms->irq_controller.domain); - sde_kms->irq_controller.domain = NULL; - } + sde_core_irq_domain_fini(sde_kms); } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 5556ef9bd2c4..ebf618635cfb 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -811,6 +811,9 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) priv = dev->dev_private; catalog = sde_kms->catalog; + ret = sde_core_irq_domain_add(sde_kms); + if (ret) + goto fail_irq; /* * Query for underlying display drivers, and create connectors, * bridges and encoders for them. @@ -869,6 +872,8 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) return 0; fail: _sde_kms_drm_obj_destroy(sde_kms); +fail_irq: + sde_core_irq_domain_fini(sde_kms); return ret; } @@ -1219,6 +1224,14 @@ static int sde_kms_hw_init(struct msm_kms *kms) goto perf_err; } + sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog); + if (IS_ERR_OR_NULL(sde_kms->hw_intr)) { + rc = PTR_ERR(sde_kms->hw_intr); + SDE_ERROR("hw_intr init failed: %d\n", rc); + sde_kms->hw_intr = NULL; + goto hw_intr_init_err; + } + /* * _sde_kms_drm_obj_init should create the DRM related objects * i.e. CRTCs, planes, encoders, connectors and so forth @@ -1244,21 +1257,12 @@ static int sde_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; - sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog); - if (IS_ERR_OR_NULL(sde_kms->hw_intr)) { - rc = PTR_ERR(sde_kms->hw_intr); - SDE_ERROR("hw_intr init failed: %d\n", rc); - sde_kms->hw_intr = NULL; - goto hw_intr_init_err; - } - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); return 0; -hw_intr_init_err: - _sde_kms_drm_obj_destroy(sde_kms); drm_obj_init_err: sde_core_perf_destroy(&sde_kms->perf); +hw_intr_init_err: perf_err: power_error: sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);