Add support for IRQ combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
The first patch prevents the ACPI core from attempting to map IRQ resources
with a valid ResourceSource as GSIs.
The first patch adds support for ResourceSource/IRQ domain mapping and
fixes IRQ probe deferral by allowing platform_device IRQ resources to be
re-initialized from the corresponding ACPI IRQ resource.
Both changes described above are conditional on the ACPI_GENERIC_GSI config.
The third patch takes advantage of the new capabilities to implement
the driver for the IRQ combiners.
Tested on top of v4.9.
Changes V8 -> V9:
* Do not attempt the mapping for non-GSI IRQs during bus scan.
* Make some public APIs private to drivers/acpi/irq.c since they are no
longer used on other modules.
Changes V7 -> V8:
* Reorder patches to allow all new code to be under drivers/acpi/irq.c.
* Change acpi_irq_get implementation to be more similar to of_irq_get
to improve maintainability.
Agustin Vega-Frias (3):
ACPI: Generic GSI: Do not attempt to map non-GSI IRQs during bus scan
ACPI: Add support for ResourceSource/IRQ domain mapping
irqchip: qcom: Add IRQ combiner driver
drivers/acpi/Makefile | 2 +-
drivers/acpi/gsi.c | 98 -----------
drivers/acpi/irq.c | 280 +++++++++++++++++++++++++++++++
drivers/acpi/resource.c | 17 +-
drivers/base/platform.c | 9 +-
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322 ++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 10 ++
9 files changed, 647 insertions(+), 101 deletions(-)
delete mode 100644 drivers/acpi/gsi.c
create mode 100644 drivers/acpi/irq.c
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
ACPI extended IRQ resources may contain a Resource Source field to specify
an alternate interrupt controller, attempting to map them as GSIs is
incorrect, so just disable the platform resource.
Since this field is currently ignored, we make this change conditional
on CONFIG_ACPI_GENERIC_GSI to keep the current behavior on x86 platforms,
in case some existing ACPI tables are using this incorrectly.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/resource.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
@@ -470,9 +482,12 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,acpi_dev_irqresource_disabled(res,0);returnfalse;}-acpi_dev_get_irqresource(res,ext_irq->interrupts[index],+if(is_gsi(ext_irq))+acpi_dev_get_irqresource(res,ext_irq->interrupts[index],ext_irq->triggering,ext_irq->polarity,ext_irq->sharable,false);+else+acpi_dev_irqresource_disabled(res,0);break;default:res->flags=0;
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
ACPI extended IRQ resources may contain a ResourceSource to specify
an alternate interrupt controller. Introduce acpi_irq_get and use it
to implement ResourceSource/IRQ domain mapping.
The new API is similar to of_irq_get and allows re-initialization
of a platform resource from the ACPI extended IRQ resource, and
provides proper behavior for probe deferral when the domain is not
yet present when called.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/Makefile | 2 +-
drivers/acpi/{gsi.c => irq.c} | 182 ++++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 9 ++-
include/linux/acpi.h | 10 +++
4 files changed, 201 insertions(+), 2 deletions(-)
rename drivers/acpi/{gsi.c => irq.c} (32%)
@@ -55,7 +55,7 @@ acpi-$(CONFIG_DEBUG_FS) += debugfs.oacpi-$(CONFIG_ACPI_NUMA)+=numa.oacpi-$(CONFIG_ACPI_PROCFS_POWER)+=cm_sbs.oacpi-y+=acpi_lpat.o-acpi-$(CONFIG_ACPI_GENERIC_GSI)+=gsi.o+acpi-$(CONFIG_ACPI_GENERIC_GSI)+=irq.oacpi-$(CONFIG_ACPI_WATCHDOG)+=acpi_watchdog.o# These are (potentially) separate modules
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/irq.csimilarity index 32%rename from drivers/acpi/gsi.crename to drivers/acpi/irq.cindex ee9e0f2..133d3f8 100644--- a/drivers/acpi/gsi.c+++ b/drivers/acpi/irq.c
@@ -85,6 +85,188 @@ void acpi_unregister_gsi(u32 gsi)EXPORT_SYMBOL_GPL(acpi_unregister_gsi);/**+*acpi_get_irq_source_fwhandle()-Retrievethefwhandleofthegiven+*acpi_resource_sourcewhichisused+*asanIRQdomainid+*@source:acpi_resource_sourcetouseforthelookup+*+*Returns:TheappropriateIRQfwhandledomainid+*NULLonfailure+*/+staticstructfwnode_handle*+acpi_get_irq_source_fwhandle(conststructacpi_resource_source*source)+{+structfwnode_handle*result;+structacpi_device*device;+acpi_handlehandle;+acpi_statusstatus;++if(!source->string_length)+returnacpi_gsi_domain_id;++status=acpi_get_handle(NULL,source->string_ptr,&handle);+if(ACPI_FAILURE(status)){+pr_warn("Could not find handle for %s\n",source->string_ptr);+returnNULL;+}++device=acpi_bus_get_acpi_device(handle);+if(!device){+pr_warn("Could not get device for %s\n",source->string_ptr);+returnNULL;+}++result=&device->fwnode;+acpi_bus_put_acpi_device(device);++returnresult;+}++/**+*ContextfortheresourcewalkusedtolookupIRQresources.+*/+structacpi_irq_parse_one_ctx{+intrc;+unsignedintindex;+unsignedlong*res_flags;+structirq_fwspec*fwspec;+};++/**+*acpi_irq_parse_one_match-HandleamatchingIRQresource+*/+staticinlinevoidacpi_irq_parse_one_match(structfwnode_handle*fwnode,+u32hwirq,u8triggering,+u8polarity,u8shareable,+structacpi_irq_parse_one_ctx*ctx)+{+ctx->rc=0;+*ctx->res_flags=acpi_dev_irq_flags(triggering,polarity,shareable);+ctx->fwspec->fwnode=fwnode;+ctx->fwspec->param[0]=hwirq;+ctx->fwspec->param[1]=acpi_dev_get_irq_type(triggering,polarity);+ctx->fwspec->param_count=2;+}++/**+*acpi_irq_parse_one_cb-Handlethegivenresource+*@ares:resourcetohandle+*@context:contextforthewalk,containsthelookupindexandreferences+*totheflagsandfwspecwheretheresultisreturned+*+*Thisiscalledbyacpi_walk_resourcespassingeachresourcereturnedby+*the_CRSmethod.WeonlyinspectIRQresources.SinceIRQresources+*mightcontainmultipleinterruptswecheckiftheindexiswithinthis+*one'sinterruptarray,otherwisewesubtractthecurrentresourceIRQ+*countfromthelookupindextoprepareforthenextresource.+*Onceamatchisfoundwecallacpi_irq_parse_one_matchtopopulate+*theresultandendthewalkbyreturningAE_CTRL_TERMINATE.+*+*ReturnAE_OKifthewalkshouldcontinue,AE_CTRL_TERMINATEifamatching+*IRQresourcewasfound.+*/+staticacpi_statusacpi_irq_parse_one_cb(structacpi_resource*ares,+void*context)+{+structacpi_irq_parse_one_ctx*ctx=context;+structacpi_resource_irq*irq;+structacpi_resource_extended_irq*eirq;+structfwnode_handle*fwnode;++switch(ares->type){+caseACPI_RESOURCE_TYPE_IRQ:+irq=&ares->data.irq;+if(ctx->index>=irq->interrupt_count){+ctx->index-=irq->interrupt_count;+returnAE_OK;+}+fwnode=acpi_gsi_domain_id;+acpi_irq_parse_one_match(fwnode,irq->interrupts[ctx->index],+irq->triggering,irq->polarity,+irq->sharable,ctx);+returnAE_CTRL_TERMINATE;+caseACPI_RESOURCE_TYPE_EXTENDED_IRQ:+eirq=&ares->data.extended_irq;+if(ctx->index>=eirq->interrupt_count){+ctx->index-=eirq->interrupt_count;+returnAE_OK;+}+fwnode=acpi_get_irq_source_fwhandle(&eirq->resource_source);+acpi_irq_parse_one_match(fwnode,eirq->interrupts[ctx->index],+eirq->triggering,eirq->polarity,+eirq->sharable,ctx);+returnAE_CTRL_TERMINATE;+}++returnAE_OK;+}++/**+*acpi_irq_parse_one-Resolveaninterruptforadevice+*@handle:thedevicewhoseinterruptistoberesolved+*@index:indexoftheinterrupttoresolve+*@fwspec:structureirq_fwspecfilledbythisfunction+*@flags:resourceflagsfilledbythisfunction+*+*ThisfunctionresolvesaninterruptforadevicebywalkingitsCRSresources+*tofindtheappropriateACPIIRQresourceandpopulatingthegivenstructure+*whichcanbeusedtoretrieveaLinuxIRQnumber.+*+*Returnstheresultstoredinctx.rcbythecallback,or-EINVALifthegiven+*indexisoutofrange.+*/+staticintacpi_irq_parse_one(acpi_handlehandle,unsignedintindex,+structirq_fwspec*fwspec,unsignedlong*flags)+{+structacpi_irq_parse_one_ctxctx={-EINVAL,index,flags,fwspec};+acpi_statusstatus;++status=acpi_walk_resources(handle,METHOD_NAME__CRS,+acpi_irq_parse_one_cb,&ctx);+if(ACPI_FAILURE(status))+return-EINVAL;+returnctx.rc;+}++/**+*acpi_irq_get-LookfortheACPIIRQresourcewiththegivenindexand+*useittoinitializethegivenLinuxIRQresource.+*@handleACPIdevicehandle+*@indexACPIIRQresourceindextolookup+*@resLinuxIRQresourcetoinitialize+*+*Return:0onsuccess+*-EINVALifanerroroccurs+*-EPROBE_DEFERiftheIRQlookup/conversionfailed+*/+intacpi_irq_get(acpi_handlehandle,unsignedintindex,structresource*res)+{+intrc;+structirq_fwspecfwspec;+structirq_domain*domain;+unsignedlongflags;++rc=acpi_irq_parse_one(handle,index,&fwspec,&flags);+if(rc)+returnrc;++domain=irq_find_matching_fwnode(fwspec.fwnode,DOMAIN_BUS_ANY);+if(!domain)+return-EPROBE_DEFER;++rc=irq_create_fwspec_mapping(&fwspec);+if(rc<=0)+return-EINVAL;++res->start=rc;+res->end=rc;+res->flags=flags;++return0;+}+EXPORT_SYMBOL_GPL(acpi_irq_get);++/***acpi_set_irq_model-SetuptheGSIirqdomaininformation*@model:thevalueassignedtoacpi_irq_model*@fwnode:theirq_domainidentifierformappingandlookingup
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Driver for interrupt combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
An interrupt combiner in this block combines a set of interrupts by
OR'ing the individual interrupt signals into a summary interrupt
signal routed to a parent interrupt controller, and provides read-
only, 32-bit registers to query the status of individual interrupts.
The status bit for IRQ n is bit (n % 32) within register (n / 32)
of the given combiner. Thus, each combiner can be described as a set
of register offsets and the number of IRQs managed.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322 ++++++++++++++++++++++++++++++++++++
3 files changed, 332 insertions(+)
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
@@ -0,0 +1,322 @@+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseversion2and+*onlyversion2aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++/*+*DriverforinterruptcombinersintheTop-levelControlandStatus+*Registers(TCSR)hardwareblockinQualcommTechnologieschips.+*Aninterruptcombinerinthisblockcombinesasetofinterruptsby+*OR'ingtheindividualinterruptsignalsintoasummaryinterrupt+*signalroutedtoaparentinterruptcontroller,andprovidesread-+*only,32-bitregisterstoquerythestatusofindividualinterrupts.+*ThestatusbitforIRQnisbit(n%32)withinregister(n/32)+*ofthegivencombiner.Thus,eachcombinercanbedescribedasaset+*ofregisteroffsetsandthenumberofIRQsmanaged.+*/++#include<linux/acpi.h>+#include<linux/irqchip/chained_irq.h>+#include<linux/irqdomain.h>+#include<linux/platform_device.h>++#define REG_SIZE 32++structcombiner_reg{+void__iomem*addr;+unsignedlongmask;+};++structcombiner{+structirq_domain*domain;+intparent_irq;+u32nirqs;+u32nregs;+structcombiner_regregs[0];+};++staticinlineu32irq_register(intirq)+{+returnirq/REG_SIZE;+}++staticinlineu32irq_bit(intirq)+{+returnirq%REG_SIZE;++}++staticinlineintirq_nr(u32reg,u32bit)+{+returnreg*REG_SIZE+bit;+}++/*+*HandlerforthecascadedIRQ.+*/+staticvoidcombiner_handle_irq(structirq_desc*desc)+{+structcombiner*combiner=irq_desc_get_handler_data(desc);+structirq_chip*chip=irq_desc_get_chip(desc);+u32reg;++chained_irq_enter(chip,desc);++for(reg=0;reg<combiner->nregs;reg++){+intvirq;+inthwirq;+u32bit;+u32status;++if(combiner->regs[reg].mask==0)+continue;++status=readl_relaxed(combiner->regs[reg].addr);+status&=combiner->regs[reg].mask;++while(status){+bit=__ffs(status);+status&=~(1<<bit);+hwirq=irq_nr(reg,bit);+virq=irq_find_mapping(combiner->domain,hwirq);+if(virq>=0)+generic_handle_irq(virq);++}+}++chained_irq_exit(chip,desc);+}++/*+*irqchipcallbacks+*/++staticvoidcombiner_irq_chip_mask_irq(structirq_data*data)+{+structcombiner*combiner=irq_data_get_irq_chip_data(data);+structcombiner_reg*reg=combiner->regs+irq_register(data->hwirq);++clear_bit(irq_bit(data->hwirq),®->mask);+}++staticvoidcombiner_irq_chip_unmask_irq(structirq_data*data)+{+structcombiner*combiner=irq_data_get_irq_chip_data(data);+structcombiner_reg*reg=combiner->regs+irq_register(data->hwirq);++set_bit(irq_bit(data->hwirq),®->mask);+}++staticstructirq_chipirq_chip={+.irq_mask=combiner_irq_chip_mask_irq,+.irq_unmask=combiner_irq_chip_unmask_irq,+.name="qcom-irq-combiner"+};++/*+*irq_domain_opscallbacks+*/++staticintcombiner_irq_map(structirq_domain*domain,unsignedintirq,+irq_hw_number_thwirq)+{+structcombiner*combiner=domain->host_data;++if(hwirq>=combiner->nirqs)+return-EINVAL;++irq_set_chip_and_handler(irq,&irq_chip,handle_level_irq);+irq_set_chip_data(irq,combiner);+irq_set_noprobe(irq);+return0;+}++staticvoidcombiner_irq_unmap(structirq_domain*domain,unsignedintirq)+{+structirq_data*data=irq_get_irq_data(irq);++if(WARN_ON(!data))+return;+irq_domain_reset_irq_data(data);+}++staticintcombiner_irq_translate(structirq_domain*d,structirq_fwspec*fws,+unsignedlong*hwirq,unsignedint*type)+{+if(is_acpi_node(fws->fwnode)){+if(WARN_ON((fws->param_count!=2)||+(fws->param[1]&IORESOURCE_IRQ_LOWEDGE)||+(fws->param[1]&IORESOURCE_IRQ_HIGHEDGE)))+return-EINVAL;++*hwirq=fws->param[0];+*type=fws->param[1];+return0;+}++return-EINVAL;+}++staticconststructirq_domain_opsdomain_ops={+.map=combiner_irq_map,+.unmap=combiner_irq_unmap,+.translate=combiner_irq_translate+};++/*+*Deviceprobing+*/++staticacpi_statuscount_registers_cb(structacpi_resource*ares,void*context)+{+int*count=context;++if(ares->type==ACPI_RESOURCE_TYPE_GENERIC_REGISTER)+++(*count);+returnAE_OK;+}++staticintcount_registers(structplatform_device*pdev)+{+structacpi_device*adev=ACPI_COMPANION(&pdev->dev);+acpi_statusstatus;+intcount=0;++if(!acpi_has_method(adev->handle,METHOD_NAME__CRS))+return-EINVAL;++status=acpi_walk_resources(adev->handle,METHOD_NAME__CRS,+count_registers_cb,&count);+if(ACPI_FAILURE(status))+return-EINVAL;+returncount;+}++structget_registers_context{+structdevice*dev;+structcombiner*combiner;+interr;+};++staticacpi_statusget_registers_cb(structacpi_resource*ares,void*context)+{+structget_registers_context*ctx=context;+structacpi_resource_generic_register*reg;+phys_addr_tpaddr;+void__iomem*vaddr;++if(ares->type!=ACPI_RESOURCE_TYPE_GENERIC_REGISTER)+returnAE_OK;++reg=&ares->data.generic_reg;+paddr=reg->address;+if((reg->space_id!=ACPI_SPACE_MEM)||+(reg->bit_offset!=0)||+(reg->bit_width>REG_SIZE)){+dev_err(ctx->dev,"Bad register resource @%pa\n",&paddr);+ctx->err=-EINVAL;+returnAE_ERROR;+}++vaddr=devm_ioremap(ctx->dev,reg->address,REG_SIZE);+if(IS_ERR(vaddr)){+dev_err(ctx->dev,"Can't map register @%pa\n",&paddr);+ctx->err=PTR_ERR(vaddr);+returnAE_ERROR;+}++ctx->combiner->regs[ctx->combiner->nregs].addr=vaddr;+ctx->combiner->nirqs+=reg->bit_width;+ctx->combiner->nregs++;+returnAE_OK;+}++staticintget_registers(structplatform_device*pdev,structcombiner*comb)+{+structacpi_device*adev=ACPI_COMPANION(&pdev->dev);+acpi_statusstatus;+structget_registers_contextctx;++if(!acpi_has_method(adev->handle,METHOD_NAME__CRS))+return-EINVAL;++ctx.dev=&pdev->dev;+ctx.combiner=comb;+ctx.err=0;++status=acpi_walk_resources(adev->handle,METHOD_NAME__CRS,+get_registers_cb,&ctx);+if(ACPI_FAILURE(status))+returnctx.err;+return0;+}++staticint__initcombiner_probe(structplatform_device*pdev)+{+structcombiner*combiner;+size_talloc_sz;+u32nregs;+interr;++nregs=count_registers(pdev);+if(nregs<=0){+dev_err(&pdev->dev,"Error reading register resources\n");+return-EINVAL;+}++alloc_sz=sizeof(*combiner)+sizeof(structcombiner_reg)*nregs;+combiner=devm_kzalloc(&pdev->dev,alloc_sz,GFP_KERNEL);+if(!combiner)+return-ENOMEM;++err=get_registers(pdev,combiner);+if(err<0)+returnerr;++combiner->parent_irq=platform_get_irq(pdev,0);+if(combiner->parent_irq<=0){+dev_err(&pdev->dev,"Error getting IRQ resource\n");+return-EPROBE_DEFER;+}++combiner->domain=irq_domain_create_linear(pdev->dev.fwnode,combiner->nirqs,+&domain_ops,combiner);+if(!combiner->domain)+/* Errors printed by irq_domain_create_linear */+return-ENODEV;++irq_set_chained_handler_and_data(combiner->parent_irq,+combiner_handle_irq,combiner);++dev_info(&pdev->dev,"Initialized with [p=%d,n=%d,r=%p]\n",+combiner->parent_irq,combiner->nirqs,combiner->regs[0].addr);+return0;+}++staticconststructacpi_device_idqcom_irq_combiner_acpi_match[]={+{"QCOM80B1",},+{}+};++staticstructplatform_driverqcom_irq_combiner_probe={+.driver={+.name="qcom-irq-combiner",+.owner=THIS_MODULE,+.acpi_match_table=ACPI_PTR(qcom_irq_combiner_acpi_match),+},+.probe=combiner_probe,+};++staticint__initregister_qcom_irq_combiner(void)+{+returnplatform_driver_register(&qcom_irq_combiner_probe);+}+device_initcall(register_qcom_irq_combiner);
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
From: Lorenzo Pieralisi <hidden> Date: 2016-12-16 16:23:23
On Wed, Dec 14, 2016 at 05:10:36PM -0500, Agustin Vega-Frias wrote:
quoted hunk
ACPI extended IRQ resources may contain a Resource Source field to specify
an alternate interrupt controller, attempting to map them as GSIs is
incorrect, so just disable the platform resource.
Since this field is currently ignored, we make this change conditional
on CONFIG_ACPI_GENERIC_GSI to keep the current behavior on x86 platforms,
in case some existing ACPI tables are using this incorrectly.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/resource.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
Well, patch is simple there is not much to say other that on the
firmware side I honestly do not see many options, either we remove the
ifdeffery above and make the check unconditional (ie we do check on
x86/ia64 too instead of always returning true) and see if things hold up
on x86 (at least we try) or we will never know and will never be able to
use this on x86 if there will ever be need.
It would be certainly weird to find out that a descriptor has a
resource_source pointer put there by mistake (because that's what we are
talking about, things work on x86/ia64 by ignoring the resource_source
pointer so any string there is just an unfortunate mistake AFAICS).
I am quite tempted to remove the ifdef and make the is_gsi() check effective on
x86/ia64 too.
Lorenzo
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
Hi Lorenzo,
On 2016-12-16 11:24, Lorenzo Pieralisi wrote:
On Wed, Dec 14, 2016 at 05:10:36PM -0500, Agustin Vega-Frias wrote:
quoted
ACPI extended IRQ resources may contain a Resource Source field to
specify
an alternate interrupt controller, attempting to map them as GSIs is
incorrect, so just disable the platform resource.
Since this field is currently ignored, we make this change conditional
on CONFIG_ACPI_GENERIC_GSI to keep the current behavior on x86
platforms,
in case some existing ACPI tables are using this incorrectly.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/resource.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
Well, patch is simple there is not much to say other that on the
firmware side I honestly do not see many options, either we remove the
ifdeffery above and make the check unconditional (ie we do check on
x86/ia64 too instead of always returning true) and see if things hold
up
on x86 (at least we try) or we will never know and will never be able
to
use this on x86 if there will ever be need.
It would be certainly weird to find out that a descriptor has a
resource_source pointer put there by mistake (because that's what we
are
talking about, things work on x86/ia64 by ignoring the resource_source
pointer so any string there is just an unfortunate mistake AFAICS).
I am quite tempted to remove the ifdef and make the is_gsi() check
effective on
x86/ia64 too.
I wouldn't be opposed to that. I added the #ifdef out of abundance of
caution,
but if the x86 folks agree and we can get sufficient testing to ensure
this
doesn't break anything I'd like to remove it too.
Thanks,
Agustin
acpi_resource *ares, int index,
acpi_dev_irqresource_disabled(res, 0);
return false;
}
- acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
+ if (is_gsi(ext_irq))
+ acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
ext_irq->triggering, ext_irq->polarity,
ext_irq->sharable, false);
+ else
+ acpi_dev_irqresource_disabled(res, 0);
break;
default:
res->flags = 0;
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Thanks.
On 2016-12-14 17:10, Agustin Vega-Frias wrote:
Add support for IRQ combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
The first patch prevents the ACPI core from attempting to map IRQ
resources
with a valid ResourceSource as GSIs.
The second patch adds support for ResourceSource/IRQ domain mapping and
fixes IRQ probe deferral by allowing platform_device IRQ resources to
be
re-initialized from the corresponding ACPI IRQ resource.
Both changes described above are conditional on the ACPI_GENERIC_GSI
config.
The third patch takes advantage of the new capabilities to implement
the driver for the IRQ combiners.
Tested on top of v4.9.
Changes V8 -> V9:
* Do not attempt the mapping for non-GSI IRQs during bus scan.
* Make some public APIs private to drivers/acpi/irq.c since they are no
longer used on other modules.
Changes V7 -> V8:
* Reorder patches to allow all new code to be under drivers/acpi/irq.c.
* Change acpi_irq_get implementation to be more similar to of_irq_get
to improve maintainability.
Agustin Vega-Frias (3):
ACPI: Generic GSI: Do not attempt to map non-GSI IRQs during bus scan
ACPI: Add support for ResourceSource/IRQ domain mapping
irqchip: qcom: Add IRQ combiner driver
drivers/acpi/Makefile | 2 +-
drivers/acpi/gsi.c | 98 -----------
drivers/acpi/irq.c | 280
+++++++++++++++++++++++++++++++
drivers/acpi/resource.c | 17 +-
drivers/base/platform.c | 9 +-
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322
++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 10 ++
9 files changed, 647 insertions(+), 101 deletions(-)
delete mode 100644 drivers/acpi/gsi.c
create mode 100644 drivers/acpi/irq.c
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
From: "Rafael J. Wysocki" <rafael@kernel.org> Date: 2017-01-03 21:56:49
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Thanks,
Rafael
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
quoted
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Thanks Rafael, I'll hold on for your feedback.
Thanks,
Rafael
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
From: Marc Zyngier <hidden> Date: 2017-01-05 16:49:16
Hi Agustin,
On 14/12/16 22:10, Agustin Vega-Frias wrote:
quoted hunk
Driver for interrupt combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
An interrupt combiner in this block combines a set of interrupts by
OR'ing the individual interrupt signals into a summary interrupt
signal routed to a parent interrupt controller, and provides read-
only, 32-bit registers to query the status of individual interrupts.
The status bit for IRQ n is bit (n % 32) within register (n / 32)
of the given combiner. Thus, each combiner can be described as a set
of register offsets and the number of IRQs managed.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322 ++++++++++++++++++++++++++++++++++++
3 files changed, 332 insertions(+)
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
@@ -0,0 +1,322 @@+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseversion2and+*onlyversion2aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++/*+*DriverforinterruptcombinersintheTop-levelControlandStatus+*Registers(TCSR)hardwareblockinQualcommTechnologieschips.+*Aninterruptcombinerinthisblockcombinesasetofinterruptsby+*OR'ingtheindividualinterruptsignalsintoasummaryinterrupt+*signalroutedtoaparentinterruptcontroller,andprovidesread-+*only,32-bitregisterstoquerythestatusofindividualinterrupts.+*ThestatusbitforIRQnisbit(n%32)withinregister(n/32)+*ofthegivencombiner.Thus,eachcombinercanbedescribedasaset+*ofregisteroffsetsandthenumberofIRQsmanaged.+*/++#include<linux/acpi.h>+#include<linux/irqchip/chained_irq.h>+#include<linux/irqdomain.h>+#include<linux/platform_device.h>++#define REG_SIZE 32++structcombiner_reg{+void__iomem*addr;+unsignedlongmask;+};++structcombiner{+structirq_domain*domain;+intparent_irq;+u32nirqs;+u32nregs;+structcombiner_regregs[0];+};++staticinlineu32irq_register(intirq)+{+returnirq/REG_SIZE;+}++staticinlineu32irq_bit(intirq)+{+returnirq%REG_SIZE;++}++staticinlineintirq_nr(u32reg,u32bit)+{+returnreg*REG_SIZE+bit;+}++/*+*HandlerforthecascadedIRQ.+*/+staticvoidcombiner_handle_irq(structirq_desc*desc)+{+structcombiner*combiner=irq_desc_get_handler_data(desc);+structirq_chip*chip=irq_desc_get_chip(desc);+u32reg;++chained_irq_enter(chip,desc);++for(reg=0;reg<combiner->nregs;reg++){+intvirq;+inthwirq;+u32bit;+u32status;++if(combiner->regs[reg].mask==0)+continue;
I'm a bit worried by this. If I understand it well, this is a pure
software construct (controlled from combiner_irq_chip_{un,}mask_irq) and
there is nothing that actually masks the interrupt at the HW level.
So if a device asserts its interrupt line, what mechanism do we have to
make sure that we don't end-up with the CPU pegged in interrupt context?
quoted hunk
++ status = readl_relaxed(combiner->regs[reg].addr);+ status &= combiner->regs[reg].mask;++ while (status) {+ bit = __ffs(status);+ status &= ~(1 << bit);+ hwirq = irq_nr(reg, bit);+ virq = irq_find_mapping(combiner->domain, hwirq);+ if (virq >= 0)
Small bug: virq == 0 shouldn't happen, since this would be an indication
that the hwirq doesn't have a mapping.
Other than the questions I have above, this now looks in a much better
shape. Hopefully Rafael will soon come back will his conclusions on the
first two patches, as I'd like to see this code to get some -next for a
while.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
Hey Marc,
On 2017-01-05 11:48, Marc Zyngier wrote:
Hi Agustin,
On 14/12/16 22:10, Agustin Vega-Frias wrote:
quoted
Driver for interrupt combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
An interrupt combiner in this block combines a set of interrupts by
OR'ing the individual interrupt signals into a summary interrupt
signal routed to a parent interrupt controller, and provides read-
only, 32-bit registers to query the status of individual interrupts.
The status bit for IRQ n is bit (n % 32) within register (n / 32)
of the given combiner. Thus, each combiner can be described as a set
of register offsets and the number of IRQs managed.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322
++++++++++++++++++++++++++++++++++++
3 files changed, 332 insertions(+)
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
@@ -0,0 +1,322 @@+/* Copyright (c) 2015-2016, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Driver for interrupt combiners in the Top-level Control and Status
+ * Registers (TCSR) hardware block in Qualcomm Technologies chips.
+ * An interrupt combiner in this block combines a set of interrupts
by
+ * OR'ing the individual interrupt signals into a summary interrupt
+ * signal routed to a parent interrupt controller, and provides read-
+ * only, 32-bit registers to query the status of individual
interrupts.
+ * The status bit for IRQ n is bit (n % 32) within register (n / 32)
+ * of the given combiner. Thus, each combiner can be described as a
set
+ * of register offsets and the number of IRQs managed.
+ */
+
+#include <linux/acpi.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
+
+#define REG_SIZE 32
+
+struct combiner_reg {
+ void __iomem *addr;
+ unsigned long mask;
+};
+
+struct combiner {
+ struct irq_domain *domain;
+ int parent_irq;
+ u32 nirqs;
+ u32 nregs;
+ struct combiner_reg regs[0];
+};
+
+static inline u32 irq_register(int irq)
+{
+ return irq / REG_SIZE;
+}
+
+static inline u32 irq_bit(int irq)
+{
+ return irq % REG_SIZE;
+
+}
+
+static inline int irq_nr(u32 reg, u32 bit)
+{
+ return reg * REG_SIZE + bit;
+}
+
+/*
+ * Handler for the cascaded IRQ.
+ */
+static void combiner_handle_irq(struct irq_desc *desc)
+{
+ struct combiner *combiner = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 reg;
+
+ chained_irq_enter(chip, desc);
+
+ for (reg = 0; reg < combiner->nregs; reg++) {
+ int virq;
+ int hwirq;
+ u32 bit;
+ u32 status;
+
+ if (combiner->regs[reg].mask == 0)
+ continue;
I'm a bit worried by this. If I understand it well, this is a pure
software construct (controlled from combiner_irq_chip_{un,}mask_irq)
and
there is nothing that actually masks the interrupt at the HW level.
So if a device asserts its interrupt line, what mechanism do we have to
make sure that we don't end-up with the CPU pegged in interrupt
context?
Yes, unfortunately this is a dumb hardware combiner; however, the real
use
of mask here is to optimize IRQ handling if the combiner instance has
its
IRQ statuses across more than one register. Currently all active
instances
only use one register, but we are getting close to 32 in one case, so I
wanted to accommodate a general case where an instance can combine more
than 32 IRQs.
Having said that, what I'm inclined to do is to remove the use of mask
on the status read form the register on the next two lines, and then let
irq_find_mapping fail if we are getting an unexpected IRQ, then call
handle_bad_irq(desc).
Do you have any other suggestions to handle the scenario? E.g., can we
safely disable the parent IRQ from this context if we see too many
spurious interrupts?
quoted
++ status = readl_relaxed(combiner->regs[reg].addr);+ status &= combiner->regs[reg].mask;++ while (status) {+ bit = __ffs(status);+ status &= ~(1 << bit);+ hwirq = irq_nr(reg, bit);+ virq = irq_find_mapping(combiner->domain, hwirq);+ if (virq >= 0)
Small bug: virq == 0 shouldn't happen, since this would be an
indication
that the hwirq doesn't have a mapping.
Other than the questions I have above, this now looks in a much better
shape. Hopefully Rafael will soon come back will his conclusions on the
first two patches, as I'd like to see this code to get some -next for a
while.
Yes, hopefully we can get to that in the following weeks.
Thanks,
Agustin
Thanks,
M.
--
Jazz is not dead. It just smells funny...
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
From: Marc Zyngier <hidden> Date: 2017-01-09 15:25:53
On 06/01/17 13:17, Agustin Vega-Frias wrote:
Hey Marc,
On 2017-01-05 11:48, Marc Zyngier wrote:
quoted
Hi Agustin,
On 14/12/16 22:10, Agustin Vega-Frias wrote:
quoted
Driver for interrupt combiners in the Top-level Control and Status
Registers (TCSR) hardware block in Qualcomm Technologies chips.
An interrupt combiner in this block combines a set of interrupts by
OR'ing the individual interrupt signals into a summary interrupt
signal routed to a parent interrupt controller, and provides read-
only, 32-bit registers to query the status of individual interrupts.
The status bit for IRQ n is bit (n % 32) within register (n / 32)
of the given combiner. Thus, each combiner can be described as a set
of register offsets and the number of IRQs managed.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/qcom-irq-combiner.c | 322
++++++++++++++++++++++++++++++++++++
3 files changed, 332 insertions(+)
create mode 100644 drivers/irqchip/qcom-irq-combiner.c
@@ -0,0 +1,322 @@+/* Copyright (c) 2015-2016, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Driver for interrupt combiners in the Top-level Control and Status
+ * Registers (TCSR) hardware block in Qualcomm Technologies chips.
+ * An interrupt combiner in this block combines a set of interrupts
by
+ * OR'ing the individual interrupt signals into a summary interrupt
+ * signal routed to a parent interrupt controller, and provides read-
+ * only, 32-bit registers to query the status of individual
interrupts.
+ * The status bit for IRQ n is bit (n % 32) within register (n / 32)
+ * of the given combiner. Thus, each combiner can be described as a
set
+ * of register offsets and the number of IRQs managed.
+ */
+
+#include <linux/acpi.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
+
+#define REG_SIZE 32
+
+struct combiner_reg {
+ void __iomem *addr;
+ unsigned long mask;
+};
+
+struct combiner {
+ struct irq_domain *domain;
+ int parent_irq;
+ u32 nirqs;
+ u32 nregs;
+ struct combiner_reg regs[0];
+};
+
+static inline u32 irq_register(int irq)
+{
+ return irq / REG_SIZE;
+}
+
+static inline u32 irq_bit(int irq)
+{
+ return irq % REG_SIZE;
+
+}
+
+static inline int irq_nr(u32 reg, u32 bit)
+{
+ return reg * REG_SIZE + bit;
+}
+
+/*
+ * Handler for the cascaded IRQ.
+ */
+static void combiner_handle_irq(struct irq_desc *desc)
+{
+ struct combiner *combiner = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 reg;
+
+ chained_irq_enter(chip, desc);
+
+ for (reg = 0; reg < combiner->nregs; reg++) {
+ int virq;
+ int hwirq;
+ u32 bit;
+ u32 status;
+
+ if (combiner->regs[reg].mask == 0)
+ continue;
I'm a bit worried by this. If I understand it well, this is a pure
software construct (controlled from combiner_irq_chip_{un,}mask_irq)
and
there is nothing that actually masks the interrupt at the HW level.
So if a device asserts its interrupt line, what mechanism do we have to
make sure that we don't end-up with the CPU pegged in interrupt
context?
Yes, unfortunately this is a dumb hardware combiner; however, the
real use of mask here is to optimize IRQ handling if the combiner
instance has its IRQ statuses across more than one register.
Currently all active instances only use one register, but we are
getting close to 32 in one case, so I wanted to accommodate a general
case where an instance can combine more than 32 IRQs.
Having said that, what I'm inclined to do is to remove the use of mask
on the status read form the register on the next two lines, and then let
irq_find_mapping fail if we are getting an unexpected IRQ, then call
handle_bad_irq(desc).
Unfortunately, having a mapping in place is not an indication that
someone can handle the interrupt. Also, you still need to handle
mask/unmask, and I don't see how you manage that, given that this
interrupt combiner seems to be a glorified OR gate.
Do you have any other suggestions to handle the scenario? E.g., can we
safely disable the parent IRQ from this context if we see too many
spurious interrupts?
I don't think so. There is two issues here:
- If a device is stuck with an active interrupt, you won't be able to
reliably detect that this is an invalid condition (the mapping trick
above is not reliable, and generic_handle_irq doesn't return anything
useful)
- Even if you could detect it, what do you do? Killing the cascade
interrupt would also kill all the other devices. Is that something
acceptable in your setup? Can you implement mask/unmask the same way?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
Hi Rafael,
On 2017-01-03 16:56, Rafael J. Wysocki wrote:
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
quoted
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Pinging again. Do you have any questions that might help with your
review? I have some minor changes I have to make to the driver itself
(patch 3) and I'd like to submit any changes you might want along with
those.
Thanks,
Agustin
Thanks,
Rafael
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
From: Marc Zyngier <hidden> Date: 2017-01-16 14:14:43
On 16/01/17 14:07, Agustin Vega-Frias wrote:
Hi Rafael,
On 2017-01-03 16:56, Rafael J. Wysocki wrote:
quoted
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
quoted
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Pinging again. Do you have any questions that might help with your
review? I have some minor changes I have to make to the driver itself
(patch 3) and I'd like to submit any changes you might want along with
those.
I'd like to add that these two initial patches are now a prerequisite
for Hanjun's series, so it'd be good to have an idea of where we're
going on that front.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
Hi Rafael,
On 2017-01-03 16:56, Rafael J. Wysocki wrote:
quoted
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
quoted
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Pinging again. Do you have any questions that might help with your
review? I have some minor changes I have to make to the driver itself
(patch 3) and I'd like to submit any changes you might want along with
those.
I'd like to add that these two initial patches are now a prerequisite
for Hanjun's series, so it'd be good to have an idea of where we're
going on that front.
Is it helpful to test patch [1-2/3] on x86 machines (with different firmware) and
an IA64 machine (surely a different version of firmware :) ) with Lorenzo's suggestion
of removing #ifdef CONFIG_ACPI_GENERIC_GSI for is_gsi()? If yes, I can do that as
I have such machines.
Thanks
Hanjun
From: Lorenzo Pieralisi <hidden> Date: 2017-01-16 14:51:28
On Mon, Jan 16, 2017 at 10:41:26PM +0800, Hanjun Guo wrote:
On 2017/1/16 22:14, Marc Zyngier wrote:
quoted
On 16/01/17 14:07, Agustin Vega-Frias wrote:
quoted
Hi Rafael,
On 2017-01-03 16:56, Rafael J. Wysocki wrote:
quoted
On Tue, Jan 3, 2017 at 4:19 PM, Agustin Vega-Frias
[off-list ref] wrote:
quoted
Hi,
Is there any more feedback on this beyond Lorenzo's suggestion to drop
the conditional check on the first patch?
How can we move forward on this series?
Essentially, I need to convince myself that patches [1-2/3] are fine
which hasn't happened yet.
Pinging again. Do you have any questions that might help with your
review? I have some minor changes I have to make to the driver itself
(patch 3) and I'd like to submit any changes you might want along with
those.
I'd like to add that these two initial patches are now a prerequisite
for Hanjun's series, so it'd be good to have an idea of where we're
going on that front.
Is it helpful to test patch [1-2/3] on x86 machines (with different firmware) and
an IA64 machine (surely a different version of firmware :) ) with Lorenzo's suggestion
of removing #ifdef CONFIG_ACPI_GENERIC_GSI for is_gsi()? If yes, I can do that as
I have such machines.
Well, it is always helpful, as helpful as getting this change into -next
as soon as possible, at the end of the day it is quite simple, as soon
as (hopefully never) we find some firmware out there (x86/ia64) that
misused the resource source field in the interrupt descriptor we will
have to add that guard back, it is as simple as that.
Thanks,
Lorenzo
ACPI extended IRQ resources may contain a Resource Source field to specify
an alternate interrupt controller, attempting to map them as GSIs is
incorrect, so just disable the platform resource.
Since this field is currently ignored, we make this change conditional
on CONFIG_ACPI_GENERIC_GSI to keep the current behavior on x86 platforms,
in case some existing ACPI tables are using this incorrectly.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/resource.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
As pointed out by Lorenzo, if the interrupt resource is a Resource Producer,
it's not GSI, so maybe the code needs to be updated as
- return ext_irq->resource_source.string_length == 0;
+ return ext_irq->resource_source.string_length == 0 &&
+ ext_irq->producer_consumer != ACPI_PRODUCER;
Thanks
Hanjun
ACPI extended IRQ resources may contain a ResourceSource to specify
an alternate interrupt controller. Introduce acpi_irq_get and use it
to implement ResourceSource/IRQ domain mapping.
The new API is similar to of_irq_get and allows re-initialization
of a platform resource from the ACPI extended IRQ resource, and
provides proper behavior for probe deferral when the domain is not
yet present when called.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/Makefile | 2 +-
drivers/acpi/{gsi.c => irq.c} | 182 ++++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 9 ++-
include/linux/acpi.h | 10 +++
4 files changed, 201 insertions(+), 2 deletions(-)
rename drivers/acpi/{gsi.c => irq.c} (32%)
[...]
quoted hunk
+/**+ * acpi_irq_parse_one_cb - Handle the given resource+ * @ares: resource to handle+ * @context: context for the walk, contains the lookup index and references+ * to the flags and fwspec where the result is returned+ *+ * This is called by acpi_walk_resources passing each resource returned by+ * the _CRS method. We only inspect IRQ resources. Since IRQ resources+ * might contain multiple interrupts we check if the index is within this+ * one's interrupt array, otherwise we subtract the current resource IRQ+ * count from the lookup index to prepare for the next resource.+ * Once a match is found we call acpi_irq_parse_one_match to populate+ * the result and end the walk by returning AE_CTRL_TERMINATE.+ *+ * Return AE_OK if the walk should continue, AE_CTRL_TERMINATE if a matching+ * IRQ resource was found.+ */+static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,+ void *context)+{+ struct acpi_irq_parse_one_ctx *ctx = context;+ struct acpi_resource_irq *irq;+ struct acpi_resource_extended_irq *eirq;+ struct fwnode_handle *fwnode;++ switch (ares->type) {+ case ACPI_RESOURCE_TYPE_IRQ:+ irq = &ares->data.irq;+ if (ctx->index >= irq->interrupt_count) {+ ctx->index -= irq->interrupt_count;+ return AE_OK;+ }+ fwnode = acpi_gsi_domain_id;+ acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],+ irq->triggering, irq->polarity,+ irq->sharable, ctx);+ return AE_CTRL_TERMINATE;+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:+ eirq = &ares->data.extended_irq;
If it's an interrupt producer, I think we don't need to map the interrupts in
any irqdomain, and return AE_CTRL_TERMINATE here.
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
eirq = &ares->data.extended_irq;
+ if (eirq->producer_consumer == ACPI_PRODUCER)
+ return AE_CTRL_TERMINATE;
if (ctx->index >= eirq->interrupt_count) {
Thanks
Hanjun
ACPI extended IRQ resources may contain a ResourceSource to specify
an alternate interrupt controller. Introduce acpi_irq_get and use it
to implement ResourceSource/IRQ domain mapping.
The new API is similar to of_irq_get and allows re-initialization
of a platform resource from the ACPI extended IRQ resource, and
provides proper behavior for probe deferral when the domain is not
yet present when called.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/Makefile | 2 +-
drivers/acpi/{gsi.c => irq.c} | 182
++++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 9 ++-
include/linux/acpi.h | 10 +++
4 files changed, 201 insertions(+), 2 deletions(-)
rename drivers/acpi/{gsi.c => irq.c} (32%)
[...]
quoted
+/**
+ * acpi_irq_parse_one_cb - Handle the given resource
+ * @ares: resource to handle
+ * @context: context for the walk, contains the lookup index and
references
+ * to the flags and fwspec where the result is returned
+ *
+ * This is called by acpi_walk_resources passing each resource
returned by
+ * the _CRS method. We only inspect IRQ resources. Since IRQ
resources
+ * might contain multiple interrupts we check if the index is within
this
+ * one's interrupt array, otherwise we subtract the current resource
IRQ
+ * count from the lookup index to prepare for the next resource.
+ * Once a match is found we call acpi_irq_parse_one_match to populate
+ * the result and end the walk by returning AE_CTRL_TERMINATE.
+ *
+ * Return AE_OK if the walk should continue, AE_CTRL_TERMINATE if a
matching
+ * IRQ resource was found.
+ */
+static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
+ void *context)
+{
+ struct acpi_irq_parse_one_ctx *ctx = context;
+ struct acpi_resource_irq *irq;
+ struct acpi_resource_extended_irq *eirq;
+ struct fwnode_handle *fwnode;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ irq = &ares->data.irq;
+ if (ctx->index >= irq->interrupt_count) {
+ ctx->index -= irq->interrupt_count;
+ return AE_OK;
+ }
+ fwnode = acpi_gsi_domain_id;
+ acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
+ irq->triggering, irq->polarity,
+ irq->sharable, ctx);
+ return AE_CTRL_TERMINATE;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ eirq = &ares->data.extended_irq;
If it's an interrupt producer, I think we don't need to map the
interrupts in
any irqdomain, and return AE_CTRL_TERMINATE here.
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
eirq = &ares->data.extended_irq;
+ if (eirq->producer_consumer == ACPI_PRODUCER)
+ return AE_CTRL_TERMINATE;
if (ctx->index >= eirq->interrupt_count) {
Agreed. I'll add the check. However, we need to return AE_OK, not
AE_CTRL_TERMINATE, since that terminates the walk and there might
be other resources to check after this one.
Thanks,
Agustin
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
ACPI extended IRQ resources may contain a Resource Source field to
specify
an alternate interrupt controller, attempting to map them as GSIs is
incorrect, so just disable the platform resource.
Since this field is currently ignored, we make this change conditional
on CONFIG_ACPI_GENERIC_GSI to keep the current behavior on x86
platforms,
in case some existing ACPI tables are using this incorrectly.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/resource.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
As pointed out by Lorenzo, if the interrupt resource is a Resource
Producer,
it's not GSI, so maybe the code needs to be updated as
- return ext_irq->resource_source.string_length == 0;
+ return ext_irq->resource_source.string_length == 0 &&
+ ext_irq->producer_consumer != ACPI_PRODUCER;
Agreed. I'll add the check.
Thanks,
Agustin
--
Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
ACPI extended IRQ resources may contain a ResourceSource to specify
an alternate interrupt controller. Introduce acpi_irq_get and use it
to implement ResourceSource/IRQ domain mapping.
The new API is similar to of_irq_get and allows re-initialization
of a platform resource from the ACPI extended IRQ resource, and
provides proper behavior for probe deferral when the domain is not
yet present when called.
Signed-off-by: Agustin Vega-Frias <redacted>
---
drivers/acpi/Makefile | 2 +-
drivers/acpi/{gsi.c => irq.c} | 182 ++++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 9 ++-
include/linux/acpi.h | 10 +++
4 files changed, 201 insertions(+), 2 deletions(-)
rename drivers/acpi/{gsi.c => irq.c} (32%)
[...]
quoted
+/**+ * acpi_irq_parse_one_cb - Handle the given resource+ * @ares: resource to handle+ * @context: context for the walk, contains the lookup index and references+ * to the flags and fwspec where the result is returned+ *+ * This is called by acpi_walk_resources passing each resource returned by+ * the _CRS method. We only inspect IRQ resources. Since IRQ resources+ * might contain multiple interrupts we check if the index is within this+ * one's interrupt array, otherwise we subtract the current resource IRQ+ * count from the lookup index to prepare for the next resource.+ * Once a match is found we call acpi_irq_parse_one_match to populate+ * the result and end the walk by returning AE_CTRL_TERMINATE.+ *+ * Return AE_OK if the walk should continue, AE_CTRL_TERMINATE if a matching+ * IRQ resource was found.+ */+static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,+ void *context)+{+ struct acpi_irq_parse_one_ctx *ctx = context;+ struct acpi_resource_irq *irq;+ struct acpi_resource_extended_irq *eirq;+ struct fwnode_handle *fwnode;++ switch (ares->type) {+ case ACPI_RESOURCE_TYPE_IRQ:+ irq = &ares->data.irq;+ if (ctx->index >= irq->interrupt_count) {+ ctx->index -= irq->interrupt_count;+ return AE_OK;+ }+ fwnode = acpi_gsi_domain_id;+ acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],+ irq->triggering, irq->polarity,+ irq->sharable, ctx);+ return AE_CTRL_TERMINATE;+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:+ eirq = &ares->data.extended_irq;
If it's an interrupt producer, I think we don't need to map the interrupts in
any irqdomain, and return AE_CTRL_TERMINATE here.
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
eirq = &ares->data.extended_irq;
+ if (eirq->producer_consumer == ACPI_PRODUCER)
+ return AE_CTRL_TERMINATE;
if (ctx->index >= eirq->interrupt_count) {
Agreed. I'll add the check. However, we need to return AE_OK, not
AE_CTRL_TERMINATE, since that terminates the walk and there might
be other resources to check after this one.
Yes, thanks for the correction, there might be other Interrupt()
resources under _CRS which needs to be scanned.
Thanks
Hanjun