From: Lina Iyer <ilina@codeaurora.org>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: tglx@linutronix.de, jason@lakedaemon.net,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
sboyd@codeaurora.org, rnayak@codeaurora.org,
asathyak@codeaurora.org
Subject: Re: [PATCH RFC v2 1/3] drivers: irqchip: pdc: Add PDC interrupt controller for QCOM SoCs
Date: Fri, 2 Feb 2018 16:40:07 +0000 [thread overview]
Message-ID: <20180202164007.GA5319@codeaurora.org> (raw)
In-Reply-To: <e1322b9a-4765-3c71-84b8-cb725fe457dd@arm.com>
On Fri, Feb 02 2018 at 16:21 +0000, Marc Zyngier wrote:
>Hi Lina,
>
>On 02/02/18 14:21, Lina Iyer wrote:
>> From : Archana Sathyakumar <asathyak@codeaurora.org>
>>
>> The Power Domain Controller (PDC) on QTI SoCs like SDM845 houses an
>> interrupt controller along with other domain control functions to handle
>> interrupt related functions like handle falling edge or active low which
>> are not detected at the GIC and handle wakeup interrupts.
>>
>> The interrupt controller is on an always-on domain for the purpose of
>> waking up the processor. Only a subset of the processor's interrupts are
>> routed through the PDC to the GIC. The PDC powers on the processors'
>> domain, when in low power mode and replays pending interrupts so the GIC
>> may wake up the processor.
>>
>> Signed-off-by: Archana Sathyakumar <asathyak@codeaurora.org>
>> Signed-off-by: Lina Iyer <ilina@codeaurora.org>
>> ---
>> +struct pdc_pin_data {
>> + int pin;
>> + int hwirq;
>> +};
>
>I seriously doubt you need this structure, see below.
>
>> +
>> +static DEFINE_SPINLOCK(pdc_lock);
>> +static void __iomem *pdc_base;
>
>You only have one of those per SoC?
>
There is only one that Linux can control.
>> +static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
>> +{
>> + int pin_out = d->hwirq;
>> + enum pdc_irq_config_bits pdc_type;
>> +
>> + switch (type) {
>> + case IRQ_TYPE_EDGE_RISING:
>> + pdc_type = PDC_RISING_EDGE;
>> + type = IRQ_TYPE_EDGE_RISING;
>> + break;
>> + case IRQ_TYPE_EDGE_FALLING:
>> + pdc_type = PDC_FALLING_EDGE;
>> + type = IRQ_TYPE_EDGE_RISING;
>> + break;
>> + case IRQ_TYPE_EDGE_BOTH:
>> + pdc_type = PDC_DUAL_EDGE;
>> + break;
>> + case IRQ_TYPE_LEVEL_HIGH:
>> + pdc_type = PDC_POLARITY_HIGH;
>> + type = IRQ_TYPE_LEVEL_HIGH;
>> + break;
>> + case IRQ_TYPE_LEVEL_LOW:
>> + pdc_type = PDC_POLARITY_LOW;
>> + type = IRQ_TYPE_LEVEL_HIGH;
>> + break;
>> + default:
>> + pdc_type = PDC_POLARITY_HIGH;
>> + break;
>
>If this default clause triggers, something is pretty wrong. You may want
>to warn and bail out instead.
>
The hardware defaults to this. I can bail out as well.
>> + }
>> +
>> + pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
>> +
>> + return irq_chip_set_type_parent(d, type);
>> +}
>> +
>> +static struct irq_chip qcom_pdc_gic_chip = {
>> + .name = "pdc-gic",
>> + .irq_eoi = irq_chip_eoi_parent,
>> + .irq_mask = qcom_pdc_gic_mask,
>> + .irq_unmask = qcom_pdc_gic_unmask,
>> + .irq_retrigger = irq_chip_retrigger_hierarchy,
>> + .irq_set_type = qcom_pdc_gic_set_type,
>> + .flags = IRQCHIP_MASK_ON_SUSPEND |
>> + IRQCHIP_SET_TYPE_MASKED |
>> + IRQCHIP_SKIP_SET_WAKE,
>> + .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
>> +#ifdef CONFIG_SMP
>> + .irq_set_affinity = irq_chip_set_affinity_parent,
>> +#endif
>> +};
>> +
>> +static irq_hw_number_t get_irq_for_pin(int pin, struct pdc_pin_data *pdc_data)
>> +{
>> + int i;
>> +
>> + for (i = 0; pdc_data[i].pin >= 0; i++)
>> + if (pdc_data[i].pin == pin)
>> + return pdc_data[i].hwirq;
>> +
>> + return pin;
>> +}
>
>This is the function that irks me. The DT already gives you a nice set
>of ranges with all the information you need. And yet, you expand the
>whole thing into at most 127 structures, wasting memory and making the
>search time a function of the number of interrupts instead of being that
>of the number of regions. Not very nice. How about something like this
>(untested):
>
Duh! Why didn't I think of this.. Thanks.
>struct pin_region {
> u32 pin_base;
> u32 parent_base;
> u32 cnt;
>};
>
>struct pin_region *pin_regions;
>int pin_region_count;
>
>static int pdc_pin_to_parent_hwirq(int pin)
>{
> int i;
>
> for (i = 0; i < pin_region_count; i++) {
> if (pin >= pin_regions[i].pin_base &&
> pin < (pin_regions[i].pin_base + pin_regions[i].cnt)
> return (pin_regions[i].parent_base + pin -
> pin_regions[i].pin_base);
> }
>
> WARN();
> return -1;
>}
>
>Less memory, less comparisons.
>
Agreed.
>> +
>> +static int qcom_pdc_translate(struct irq_domain *d,
>> + struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
>> +{
>> + if (is_of_node(fwspec->fwnode)) {
>> + if (fwspec->param_count < 3)
>> + return -EINVAL;
>
>Why 3? Reading the DT binding, this is indeed set to 3 without any
>reason. I'd suggest this becomes 2, encoding the pin number and the
>trigger information, as the leading 0 is quite useless. Yes, I know
>other examples in the kernel are using this 0, and that was a
>consequence of retrofitting the omitted interrupt controllers (back in
>the days of the stupid gic_arch_extn...). Don't do that.
>
>> +
>> + *hwirq = fwspec->param[1];
>> + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
>
>... and fix this accordingly.
>
>> + return 0;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static int qcom_pdc_alloc(struct irq_domain *domain,
>> + unsigned int virq, unsigned int nr_irqs, void *data)
>> +{
>> + struct irq_fwspec *fwspec = data;
>> + struct irq_fwspec parent_fwspec;
>> + irq_hw_number_t hwirq, parent_hwirq;
>> + unsigned int type;
>> + int ret;
>> +
>> + ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
>> + if (ret)
>> + return -EINVAL;
>> +
>> + parent_hwirq = get_irq_for_pin(hwirq, domain->host_data);
>> + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
>> + &qcom_pdc_gic_chip, (void *)parent_hwirq);
>> + if (ret)
>> + return ret;
>> +
>> + if (type & IRQ_TYPE_EDGE_BOTH)
>> + type = IRQ_TYPE_EDGE_RISING;
>> +
>> + if (type & IRQ_TYPE_LEVEL_MASK)
>> + type = IRQ_TYPE_LEVEL_HIGH;
>> +
>> + parent_fwspec = *fwspec;
>> + parent_fwspec.param[1] = parent_hwirq;
>> + parent_fwspec.param[2] &= ~IRQ_TYPE_SENSE_MASK;
>> + parent_fwspec.param[2] |= type;
>> + parent_fwspec.fwnode = domain->parent->fwnode;
>
>This becomes:
>
> parent_fwspec.fwnode = domain->parent->fwnode;
> parent_fwspec.param_count = 3; // That's what the GIC wants
> parent_fwspec.param[0] = 0; //GIC_SPI
> parent_fwspec.param[1] = parent_hwirq;
> parent_fwspec.param[2] = type;
>
Sure.
>> +
>> + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
>> + &parent_fwspec);
>> +}
>> +
>> +static const struct irq_domain_ops qcom_pdc_ops = {
>> + .translate = qcom_pdc_translate,
>> + .alloc = qcom_pdc_alloc,
>> + .free = irq_domain_free_irqs_common,
>> +};
>> +
>> +static int pdc_setup_pin_mapping(struct device_node *np,
>> + struct pdc_pin_data **data)
>> +{
>> + int ret;
>> + int n, i, j, k, pins = 0;
>> + int *val;
>> + struct pdc_pin_data *map;
>> +
>> + n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
>> + if (!n || n % 3)
>> + return -EINVAL;
>> +
>> + val = kcalloc(n, sizeof(u32), GFP_KERNEL);
>> + if (!val)
>> + return -ENOMEM;
>> +
>> + ret = of_property_read_u32_array(np, "qcom,pdc-ranges", val, n);
>> + if (ret)
>> + return ret;
>
>Memory leak.
>
Ok.
>> +
>> + for (i = 0; i < n; i += 3)
>> + pins += val[i + 2];
>> +
>> + if (pins > PDC_MAX_IRQS)
>> + return -EFAULT;
>
>EFAULT is for an actual page fault. If you get one here, you have
>bigger problems. EINVAL is better. is You're also leaking memory.
>
Ok.
>> +
>> + map = kcalloc(pins + 1, sizeof(*map), GFP_KERNEL);
>> + if (!map) {
>> + ret = -ENOMEM;
>> + goto fail;
>> + }
>> +
>> + for (i = 0, k = 0; i < n; i += 3) {
>> + for (j = 0; j < val[i + 2]; j++, k++) {
>> + map[k].pin = val[i] + j;
>> + map[k].hwirq = val[i + 1] + j;
>> + }
>> + }
>
>That's the thing that needs to go. Just store the ranges as exposed by
>the DT, maybe with some checking that there is no overlap in the
>ranges (not that it matters much...).
>
Makes sense.
Thanks,
Lina
next prev parent reply other threads:[~2018-02-02 16:40 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-02 14:21 [PATCH RFC v2 0/3] irqchip: qcom: add support for PDC interrupt controller Lina Iyer
2018-02-02 14:21 ` [PATCH RFC v2 1/3] drivers: irqchip: pdc: Add PDC interrupt controller for QCOM SoCs Lina Iyer
2018-02-02 14:58 ` Marc Zyngier
2018-02-02 16:40 ` Lina Iyer [this message]
2018-02-02 15:37 ` Thomas Gleixner
2018-02-02 16:41 ` Lina Iyer
[not found] ` <20180202142200.6229-1-ilina-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2018-02-02 14:21 ` [PATCH RFC v2 2/3] dt-bindings/interrupt-controller: pdc: descibe PDC device binding Lina Iyer
2018-02-02 16:28 ` Marc Zyngier
[not found] ` <396cfc2f-7deb-0c93-7178-d9f5524f110e-5wv7dgnIgG8@public.gmane.org>
2018-02-02 16:46 ` Lina Iyer
2018-02-02 17:02 ` Marc Zyngier
2018-02-02 14:22 ` [PATCH RFC v2 3/3] drivers: irqchip: pdc: log PDC info in FTRACE Lina Iyer
2018-02-02 15:57 ` Thomas Gleixner
2018-02-02 23:02 ` Lina Iyer
2018-02-05 15:18 ` Lina Iyer
2018-02-05 16:57 ` Steven Rostedt
2018-02-02 16:32 ` Steven Rostedt
2018-02-02 22:53 ` Lina Iyer
2018-02-05 15:50 ` Lina Iyer
2018-02-05 17:00 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180202164007.GA5319@codeaurora.org \
--to=ilina@codeaurora.org \
--cc=asathyak@codeaurora.org \
--cc=jason@lakedaemon.net \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=rnayak@codeaurora.org \
--cc=sboyd@codeaurora.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).