xen: arm: Parse PCI DT nodes' ranges and interrupt-map
v3 cover xen: arm: Parse PCI DT nodes' ranges and interrupt-map
This series adds parsing of the DT ranges and interrupt-map properties for PCI devices, these contain the MMIOs and IRQs used by children on the bus. This replaces the specific mapping stuff on xgene.
Since last time I've made the irq iterator pass a translated IRQ to the callback and (hopefully) arranged to handle devices which have been reserved for passthrough somewhat correctly.
Ian.
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
PATCH v4 1/6 xen: dt: add dt_for_each_irq_map helper
This function iterates over a nodes interrupt-map property and calls a callback for each interrupt. For now it only supplies the translated IRQ since my use case has no need of e.g. child unit address. These can be added as needed by any future users.
This follows much the same logic as dt_irq_map_raw when parsing the interrupt-map, but doesn't walk up the tree doing the actual translation and it iterates over all entries instead of just looking for the first match.
I looked into refactoring dt_irq_map_raw but I couldn't find a way which I was confident in, plus I was reluctant to diverge from the Linux roots of this function any further.
---
v4: Pass a dt_irq not a dt_irq_raw to the callback.
--- xen/common/device_tree.c | 148 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 12 ++++ 2 files changed, 160 insertions(+)
xen/common/device_tree.c +148 -0
@@ -811,6 +811,154 @@ unsigned int dt_number_of_address(const struct dt_device_node *dev)return (psize / onesize); } +int dt_for_each_irq_map (const struct dt_device_node *dev, +int (*cb)(const struct dt_device_node *, +const struct dt_irq *, +void *), +void *data) +{ +const struct dt_device_node *ipar, *tnode, *old =NULL ; +const __be32 *tmp, *imap; +u32 intsize =1 , addrsize, pintsize =0 , paddrsize =0 ; +u32 imaplen; +int i, ret; + +struct dt_raw_irq dt_raw_irq; +struct dt_irq dt_irq; + +dt_dprintk ("%s: par=%s cb=%p data=%p\n" , __func__, + dev->full_name, cb, data); + + ipar = dev; + +/* First get the #interrupt-cells property of the current cursor +* that tells us how to interpret the passed-in intspec. If there +* is none, we are nice and just walk up the tree +*/ +do { + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp !=NULL ) + { + intsize =be32_to_cpu (*tmp); +break ; + } + tnode = ipar; + ipar =dt_irq_find_parent (ipar); + }while ( ipar ); +if ( ipar ==NULL ) + { +dt_dprintk (" -> no parent found !\n" ); + goto fail; + } + +dt_dprintk ("%s: ipar=%s, size=%d\n" , __func__, ipar->full_name, intsize); + +if ( intsize >DT_MAX_IRQ_SPEC ) + { +dt_dprintk (" -> too many irq specifier cells\n" ); + goto fail; + } + +/* Look for this #address-cells. We have to implement the old linux +* trick of looking for the parent here as some device-trees rely on it +*/ + old = ipar; +do { + tmp =dt_get_property (old,"#address-cells" ,NULL ); + tnode =dt_get_parent (old); + old = tnode; + }while ( old && tmp ==NULL ); + + old =NULL ; + addrsize = (tmp ==NULL ) ?2 :be32_to_cpu (*tmp); + +dt_dprintk (" -> addrsize=%d\n" , addrsize); + +/* Now look for an interrupt-map */ + imap =dt_get_property (dev,"interrupt-map" , &imaplen); +/* No interrupt map, check for an interrupt parent */ +if ( imap ==NULL ) + { +dt_dprintk (" -> no map, ignoring\n" ); + goto fail; + } + imaplen /=sizeof (u32); + +/* Parse interrupt-map */ +while ( imaplen > (addrsize + intsize +1 ) ) + { +/* skip child unit address and child interrupt specifier */ + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + +/* Get the interrupt parent */ + ipar =dt_find_node_by_phandle (be32_to_cpup (imap)); + imap++; + --imaplen; + +/* Check if not found */ +if ( ipar ==NULL ) + { +dt_dprintk (" -> imap parent not found !\n" ); + goto fail; + } + +dt_dprintk (" -> ipar %s\n" ,dt_node_name (ipar)); + +/* Get #interrupt-cells and #address-cells of new +* parent +*/ + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp ==NULL ) + { +dt_dprintk (" -> parent lacks #interrupt-cells!\n" ); + goto fail; + } + pintsize =be32_to_cpu (*tmp); + tmp =dt_get_property (ipar,"#address-cells" ,NULL ); + paddrsize = (tmp ==NULL ) ?0 :be32_to_cpu (*tmp); + +dt_dprintk (" -> pintsize=%d, paddrsize=%d\n" , + pintsize, paddrsize); + +/* Check for malformed properties */ +if ( imaplen < (paddrsize + pintsize) ) + goto fail; + + imap += paddrsize; + imaplen -= paddrsize; + + dt_raw_irq.controller = ipar; + dt_raw_irq.size = pintsize; +for ( i =0 ; i < pintsize; i++ ) + dt_raw_irq.specifier[i] =dt_read_number (imap + i,1 ); + + ret =dt_irq_translate (&dt_raw_irq, &dt_irq); +if ( ret <0 ) + { +dt_dprintk (" -> failed to translate IRQ: %d\n" , ret); +return ret; + } + + ret =cb (dev, &dt_irq, data); +if ( ret <0 ) + { +dt_dprintk (" -> callback failed=%d\n" , ret); +return ret; + } + + imap += pintsize; + imaplen -= pintsize; + +dt_dprintk (" -> imaplen=%d\n" , imaplen); + } + +return 0 ; + +fail: +return -EINVAL ; +} +/** * dt_irq_map_raw - Low level interrupt tree parsing * @parent: the device interrupt parent
xen/include/xen/device_tree.h +12 -0
@@ -528,6 +528,18 @@ int dt_device_get_raw_irq(const struct dt_device_node *device,int dt_irq_translate (const struct dt_raw_irq *raw,struct dt_irq *out_irq);/** +* dt_for_each_irq_map - Iterate over a nodes interrupt-map property +* @dev: The node whose interrupt-map property should be iterated over +* @cb: Call back to call for each entry +* @data: Caller data passed to callback +*/ +int dt_for_each_irq_map (const struct dt_device_node *dev, +int (*cb)(const struct dt_device_node *, +const struct dt_irq *, +void *), +void *data); + +/** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value *
Signature · 1 line
1.7.10.4
Re: [PATCH v4 1/6] xen: dt: add dt_for_each_irq_map helper
Hi Ian,
Quoted 10 lines · Ian Campbell
This function iterates over a nodes interrupt-map property and calls a callback for each interrupt. For now it only supplies the translated IRQ since my use case has no need of e.g. child unit address. These can be added as needed by any future users.
This follows much the same logic as
dt_irq_map_rawwhen parsing the interrupt-map, but doesn't walk up the tree doing the actual translation and it iterates over all entries instead of just looking for the first match.
Quoted 5 lines
I looked into refactoring
dt_irq_map_rawbut I couldn't find a way which I was confident in, plus I was reluctant to diverge from the Linux roots of this function any further.Signed-off-by Ian Campbell <[email protected]>
Quoted 39 lines
---
v4: Pass adt_irqnot adt_irq_rawto the callback.--- xen/common/device_tree.c | 148 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 12 ++++ 2 files changed, 160 insertions(+)xen/common/device_tree.c +24
-0@@ -811,6 +811,154 @@ unsigned int dt_number_of_address(const struct dt_device_node *dev)return (psize / onesize); } +int dt_for_each_irq_map (const struct dt_device_node *dev, +int (*cb)(const struct dt_device_node *, +const struct dt_irq *, +void *), +void *data) +{ +const struct dt_device_node *ipar, *tnode, *old =NULL ; +const __be32 *tmp, *imap; +u32 intsize =1 , addrsize, pintsize =0 , paddrsize =0 ; +u32 imaplen; +int i, ret; + +struct dt_raw_irq dt_raw_irq; +struct dt_irq dt_irq; + +dt_dprintk ("%s: par=%s cb=%p data=%p\n" , __func__, + dev->full_name, cb, data); + + ipar = dev; + +/* First get the #interrupt-cells property of the current cursor +* that tells us how to interpret the passed-in intspec. If there +* is none, we are nice and just walk up the tree +*/
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 847
Quoted 10 lines
xen/common/device_tree.c +10
-0+do { + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp !=NULL ) + { + intsize =be32_to_cpu (*tmp); +break ; + } + tnode = ipar; + ipar =dt_irq_find_parent (ipar); + }while ( ipar );
This loop doesn't seem useful. AFAIU the spec, the PCI node (i.e your variable dev) will always have property #interrupt-cells. We will break directly.
[..]
Quoted 5 lines
xen/common/device_tree.c +5
-0+if ( intsize >DT_MAX_IRQ_SPEC ) + { +dt_dprintk (" -> too many irq specifier cells\n" ); + goto fail; + }
[..]
Quoted 9 lines
xen/common/device_tree.c +9
-0+/* Parse interrupt-map */ +while ( imaplen > (addrsize + intsize +1 ) ) + { +/* skip child unit address and child interrupt specifier */ + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + +/* Get the interrupt parent */ + ipar =dt_find_node_by_phandle (be32_to_cpup (imap));
[..]
Quoted 10 lines
xen/common/device_tree.c +10
-0+/* Get #interrupt-cells and #address-cells of new +* parent +*/ + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp ==NULL ) + { +dt_dprintk (" -> parent lacks #interrupt-cells!\n" ); + goto fail; + } + pintsize =be32_to_cpu (*tmp);
[..]
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 932
Quoted 2 lines
xen/common/device_tree.c +2
-0+ dt_raw_irq.controller = ipar; + dt_raw_irq.size = pintsize;
Don't you need to check that pintsize is < DT_MAX_IRQ_SPEC?
The previous "if ( ... > DT_MAX_IRQ_SPEC )" will likely be done on a different parent.
For instance with the following incomplete DT (based on the apm-storm.dsi in Linux):
pcie0 {
#interrupt-cells = <1>;
...
#interrupt-map = < 0x0 0x0 0x0 0x1 &gic ... >
}
The first ipar will point to pcie0 because it has a property "#interrupt-cells", while the second time ipar will point to the gic node.
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 937
Quoted 5 lines
xen/common/device_tree.c +5
-0+for ( i =0 ; i < pintsize; i++ ) + dt_raw_irq.specifier[i] =dt_read_number (imap + i,1 ); + + ret =dt_irq_translate (&dt_raw_irq, &dt_irq); +if ( ret <0 )
The other caller of dt_irq_translate returns an error when ret is not 0. I would do the same here.
Regards,
Signature · 1 line
Julien Grall
Re: [PATCH v4 1/6] xen: dt: add dt_for_each_irq_map helper
Quoted 15 lines · Julien Grall
Quoted 4 lines
xen/common/device_tree.c +4
-0+/* First get the #interrupt-cells property of the current cursor +* that tells us how to interpret the passed-in intspec. If there +* is none, we are nice and just walk up the tree +*/ xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 847
Quoted 10 lines
xen/common/device_tree.c +10
-0+do { + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp !=NULL ) + { + intsize =be32_to_cpu (*tmp); +break ; + } + tnode = ipar; + ipar =dt_irq_find_parent (ipar); + }while ( ipar );
Quoted 3 lines
This loop doesn't seem useful. AFAIU the spec, the PCI node (i.e your variable dev) will always have property #interrupt-cells. We will break directly.
The reason for this is explained in the comment i.e. "we are nice" to broken trees.
This code is from Linux, via dt_irq_map_raw, I don't fancy messing with it too much.
Quoted 6 lines
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 932
Quoted 2 lines
xen/common/device_tree.c +2
-0+ dt_raw_irq.controller = ipar; + dt_raw_irq.size = pintsize;Don't you need to check that pintsize is <
DT_MAX_IRQ_SPEC? The previous "if ( ... >DT_MAX_IRQ_SPEC)" will likely be done on a different parent.
Yes, I think that would be a good idea.
Quoted 13 lines
For instance with the following incomplete DT (based on the apm-storm.dsi in Linux):
pcie0 { #interrupt-cells = <1>; ... #interrupt-map = < 0x0 0x0 0x0 0x1 &gic ... > }The first ipar will point to pcie0 because it has a property "#interrupt-cells", while the second time ipar will point to the gic node.
Quoted 8 lines
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 937
Quoted 5 lines
xen/common/device_tree.c +5
-0+for ( i =0 ; i < pintsize; i++ ) + dt_raw_irq.specifier[i] =dt_read_number (imap + i,1 ); + + ret =dt_irq_translate (&dt_raw_irq, &dt_irq); +if ( ret <0 )The other caller of
dt_irq_translatereturns an error when ret is not 0. I would do the same here.
dt_device_get_irq just returns the value of dt_irq_translate directly.
Are you suggesting this code should treat positive results as an error as well as negative ones? I don't agree, this function has the normal 0 on success -ve on error semantics AFAICT.
Or did you mean something else?
Ian.
Re: [PATCH v4 1/6] xen: dt: add dt_for_each_irq_map helper
Quoted 21 lines · Ian Campbell
Quoted 15 lines · Julien Grall
Quoted 4 lines
xen/common/device_tree.c +4
-0+/* First get the #interrupt-cells property of the current cursor +* that tells us how to interpret the passed-in intspec. If there +* is none, we are nice and just walk up the tree +*/ xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 847
Quoted 10 lines
xen/common/device_tree.c +10
-0+do { + tmp =dt_get_property (ipar,"#interrupt-cells" ,NULL ); +if ( tmp !=NULL ) + { + intsize =be32_to_cpu (*tmp); +break ; + } + tnode = ipar; + ipar =dt_irq_find_parent (ipar); + }while ( ipar );Quoted 3 lines
This loop doesn't seem useful. AFAIU the spec, the PCI node (i.e your variable dev) will always have property #interrupt-cells. We will break directly.
Quoted 5 lines
The reason for this is explained in the comment i.e. "we are nice" to broken trees.
This code is from Linux, via
dt_irq_map_raw, I don't fancy messing with it too much.
Ok. Let's stick with that.
Quoted 28 lines
Quoted 6 lines
xen/common/device_tree.c unsigned int dt_number_of_address(const struct dt_device_node *dev) · line 932
Quoted 2 lines
xen/common/device_tree.c +2
-0+ dt_raw_irq.controller = ipar; + dt_raw_irq.size = pintsize;Don't you need to check that pintsize is <
DT_MAX_IRQ_SPEC? The previous "if ( ... >DT_MAX_IRQ_SPEC)" will likely be done on a different parent.Yes, I think that would be a good idea.
Quoted 19 lines
For instance with the following incomplete DT (based on the apm-storm.dsi in Linux):
pcie0 { #interrupt-cells = <1>; ... #interrupt-map = < 0x0 0x0 0x0 0x1 &gic ... > }The first ipar will point to pcie0 because it has a property "#interrupt-cells", while the second time ipar will point to the gic node.
Quoted 5 lines
xen/common/device_tree.c +5
-0+for ( i =0 ; i < pintsize; i++ ) + dt_raw_irq.specifier[i] =dt_read_number (imap + i,1 ); + + ret =dt_irq_translate (&dt_raw_irq, &dt_irq); +if ( ret <0 )
Quoted 4 lines
Quoted 2 lines
The other caller of
dt_irq_translatereturns an error when ret is not 0. I would do the same here.
dt_device_get_irqjust returns the value ofdt_irq_translatedirectly.
But the caller of dt_device_get_irq is treating everything other than 0 as an error.
Quoted 4 lines
Are you suggesting this code should treat positive results as an error as well as negative ones? I don't agree, this function has the normal 0 on success -ve on error semantics AFAICT.
Well, it's not documented so it can be interpreted differently. I personally interpreted as anything other than 0 is an error. This is how Linux behave on most of the of_* function and I think it's "safer".
Regards,
Signature · 1 line
Julien Grall
Re: [PATCH v4 1/6] xen: dt: add dt_for_each_irq_map helper
Quoted 10 lines · Julien Grall
Quoted 4 lines
Quoted 2 lines
The other caller of
dt_irq_translatereturns an error when ret is not 0. I would do the same here.
dt_device_get_irqjust returns the value ofdt_irq_translatedirectly.But the caller of
dt_device_get_irqis treating everything other than 0 as an error.Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Are you suggesting this code should treat positive results as an error as well as negative ones? I don't agree, this function has the normal 0 on success -ve on error semantics AFAICT.
Well, it's not documented so it can be interpreted differently.
It's not documented, but it's pretty conventional throughout most Linux interfaces...
Quoted 3 lines
I
personally interpreted as anything other than 0 is an error. This is how Linux behave on most of the of_* function and I think it's "safer".
...but it does look like of_* (which are dt_* in Xen) do indeed behave that way so I shall change it.
I'm going to change the two cb invocations for consistency too.
Ian.
PATCH v4 2/6 xen: dt: add dt_for_each_range helper
In reply to Ian CampbellThis function iterates over a node's ranges property and calls a callback for each region. For now it only supplies the MMIO range (in terms of CPU addresses, i.e. already translated).
--- xen/common/device_tree.c | 85 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 12 ++++++ 2 files changed, 97 insertions(+)
xen/common/device_tree.c +85 -0
@@ -704,6 +704,91 @@ int dt_device_get_address(const struct dt_device_node *dev, unsigned int index,return 0 ; } + +int dt_for_each_range (const struct dt_device_node *dev, +int (*cb)(const struct dt_device_node *, +u64 addr,u64 length, +void *), +void *data) +{ +const struct dt_device_node *parent =NULL ; +const struct dt_bus *bus, *pbus; +const __be32 *ranges; +__be32 addr[DT_MAX_ADDR_CELLS ]; +unsigned int rlen; +int na, ns, pna, pns, rone; + + bus =dt_match_bus (dev); +if ( !bus ) +return 0 ;/* device is not a bus */ + + parent =dt_get_parent (dev); +if ( parent ==NULL ) +return -EINVAL ; + + ranges =dt_get_property (dev,"ranges" , &rlen); +if ( ranges ==NULL ) + { +printk (XENLOG_ERR "DT: no ranges; cannot enumerate\n" ); +return -EINVAL ; + } +if ( rlen ==0 )/* Nothing to do */ +return 0 ; + + bus->count_cells (dev, &na, &ns); +if ( !DT_CHECK_COUNTS (na, ns) ) + { +printk (XENLOG_ERR "dt_parse: Bad cell count for device %s\n" , + dev->full_name); +return -EINVAL ; + } + + pbus =dt_match_bus (parent); +if ( pbus ==NULL ) + { +printk ("DT: %s is not a valid bus\n" , parent->full_name); +return -EINVAL ; + } + + pbus->count_cells (dev, &pna, &pns); +if ( !DT_CHECK_COUNTS (pna, pns) ) + { +printk (XENLOG_ERR "dt_parse: Bad cell count for parent %s\n" , + dev->full_name); +return -EINVAL ; + } + +/* Now walk through the ranges */ + rlen /=4 ; + rone = na + pna + ns; + +dt_dprintk ("%s: dev=%s, bus=%s, parent=%s, rlen=%d, rone=%d\n" , + __func__, +dt_node_name (dev), bus->name, +dt_node_name (parent), rlen, rone); + +for ( ; rlen >= rone; rlen -= rone, ranges += rone ) + { +u64 a, s; +int ret; + +memcpy (addr, ranges + na,4 * pna); + + a =__dt_translate_address (dev, addr,"ranges" ); + s =dt_read_number (ranges + na + pna, ns); + + ret =cb (dev, a, s, data); +if ( ret <0 ) + { +dt_dprintk (" -> callback failed=%d\n" , ret); +return ret; + } + + } + +return 0 ; +} +/** * dt_find_node_by_phandle - Find a node given a phandle * @handle: phandle of the node to find
xen/include/xen/device_tree.h +12 -0
@@ -540,6 +540,18 @@ int dt_for_each_irq_map(const struct dt_device_node *dev, void *data);/** +* dt_for_each_range - Iterate over a nodes ranges property +* @dev: The node whose interrupt-map property should be iterated over +* @cb: Call back to call for each entry +* @data: Caller data passed to callback +*/ +int dt_for_each_range (const struct dt_device_node *dev, +int (*cb)(const struct dt_device_node *, +u64 addr,u64 length, +void *), +void *data); + +/** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value *
Signature · 1 line
1.7.10.4
PATCH v4 3/6 xen: arm: slightly refactor gic DT node creation for domain 0.
In reply to Ian CampbellAlthough in principal #interrupt-cells can vary it must always be 3 for a GIC (and we only support GIC as a guest interrupt controller), so putting it in common code is OK.
---
v3: Retitle and reword, was "xen: arm: propagate gic's
#interrupt-cells property to dom0."
v4: Drop spurious "all gics" from the commit log.
--- xen/arch/arm/domain_build.c | 8 ++++++++ xen/arch/arm/gic-hip04.c | 9 --------- xen/arch/arm/gic-v2.c | 9 --------- xen/arch/arm/gic-v3.c | 8 -------- 4 files changed, 8 insertions(+), 26 deletions(-)
xen/arch/arm/domain_build.c +8 -0
@@ -847,6 +847,14 @@ static int make_gic_node(const struct domain *d, void *fdt,return res; } + res =fdt_property_cell (fdt,"#interrupt-cells" ,3 ); +if ( res ) +return res; + + res =fdt_property (fdt,"interrupt-controller" ,NULL ,0 ); +if ( res ) +return res; + res =fdt_end_node (fdt);return res;
xen/arch/arm/gic-hip04.c +0 -9
@@ -636,15 +636,6 @@ static int hip04gic_make_dt_node(const struct domain *d,if ( res )return res; - res =fdt_property_cell (fdt,"#interrupt-cells" ,3 ); -if ( res ) -return res; - - res =fdt_property (fdt,"interrupt-controller" ,NULL ,0 ); - -if ( res ) -return res; -/* * DTB provides up to 4 regions to handle virtualization * (in order GICD, GICC, GICH and GICV interfaces)
xen/arch/arm/gic-v2.c +0 -9
@@ -624,15 +624,6 @@ static int gicv2_make_dt_node(const struct domain *d,if ( res )return res; - res =fdt_property_cell (fdt,"#interrupt-cells" ,3 ); -if ( res ) -return res; - - res =fdt_property (fdt,"interrupt-controller" ,NULL ,0 ); - -if ( res ) -return res; -/* * DTB provides up to 4 regions to handle virtualization * (in order GICD, GICC, GICH and GICV interfaces)
xen/arch/arm/gic-v3.c +0 -8
@@ -1106,14 +1106,6 @@ static int gicv3_make_dt_node(const struct domain *d,if ( res )return res; - res =fdt_property_cell (fdt,"#interrupt-cells" ,3 ); -if ( res ) -return res; - - res =fdt_property (fdt,"interrupt-controller" ,NULL ,0 ); -if ( res ) -return res; - res =dt_property_read_u32 (gic,"redistributor-stride" , &rd_stride);if ( !res ) rd_stride =0 ;
Signature · 1 line
1.7.10.4
Re: [PATCH v4 3/6] xen: arm: slightly refactor gic DT node creation for domain 0.
Quoted 6 lines · Ian Campbell
Although in principal #interrupt-cells can vary it must always be 3 for a GIC (and we only support GIC as a guest interrupt controller), so putting it in common code is OK.
Signed-off-by Ian Campbell <[email protected]>Reviewed-by Julien Grall <[email protected]>
applied along with Suravee's "xen/arm: gic: Refactor the code for creating gic node" from the gicv2m series.
Ian.
PATCH v4 4/6 xen: arm: drop redundant extra call to vgic_reserve_virq
In reply to Ian CampbellThis is only needed if we are giving the IRQ to dom0 (as opposed to setting it up for passthrough due to xen,passthrough property). There is already a call to vgic_reserve_virq inside the if ( need_mapping ), so drop this one.
---
v4: New patch
--- xen/arch/arm/domain_build.c | 6 ------ 1 file changed, 6 deletions(-)
xen/arch/arm/domain_build.c +0 -6
@@ -1005,12 +1005,6 @@ static int handle_device(struct domain *d, struct dt_device_node *dev) irq = res;DPRINT ("irq %u = %u\n" , i, irq); -/* -* Checking the return of vgic_reserve_virq is not -* necessary. It should not fail except when we try to map -* the IRQ twice. This can legitimately happen if the IRQ is shared -*/ -vgic_reserve_virq (d, irq); res =irq_permit_access (d, irq);if ( res )
Signature · 1 line
1.7.10.4
Re: [PATCH v4 4/6] xen: arm: drop redundant extra call to vgic_reserve_virq
Hi Ian,
Quoted 6 lines · Ian Campbell
This is only needed if we are giving the IRQ to dom0 (as opposed to setting it up for passthrough due to xen,passthrough property). There is already a call to
vgic_reserve_virqinside the if (need_mapping), so drop this one.Signed-off-by Ian Campbell <[email protected]>
Regards,
Signature · 1 line
Julien Grall
PATCH v4 5/6 xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
In reply to Ian CampbellThis uses the dt_for_each_{irq_map,range} helpers to map the interrupt and child MMIO regions to dom0. Since PCI busses are enumerable these resources may not be otherwise described in the DT (although they can be).
Although PCI is the only bus we handle this way the code should be generic enough to apply to similar buses in the future.
This replaces the xgene specific mapping. Tested on Mustang and on a model with a PCI virtio controller.
This patch doesn't stop recursing when it finds such a node, since double mapping these resources if they do happen to be described is (or should be) harmless
---
v2: This is essentially a complete reworking, which actually parses things properly (obeying #{address,size,interrupt}-cells on the appriopriate nodes) and includes handling of interrupt-map too.
v3: Use dt_for_each_ranges and refactor handling into
handle_device_children.
Retitled from "xen: arm: handle PCI DT node ranges and interrupt-map properties" and rewrote much of the commit message.
This change also essentially obsoleted any discussion about logging unhandled buses since it no longer makes sense (or at least there is nothing convenient to hang it off)
v4: dt_for_each_irq_map now provides the translated IRQ, so adjust
accordingly.
Call irq_permit_access to allow dom0 to passthrough the device to another domain.
Only call route_irq_to_guest, map_mmio_regions and (newly added call to) vgic_reserve_virq if the device is not marked as reserved for passthrough.
--- xen/arch/arm/domain_build.c | 121 ++++++++++++++++++++++++++++ xen/arch/arm/platforms/xgene-storm.c | 143 ---------------------------------- 2 files changed, 121 insertions(+), 143 deletions(-)
xen/arch/arm/domain_build.c +121 -0
@@ -935,6 +935,123 @@ static int make_timer_node(const struct domain *d, void *fdt,return res; } +static int map_interrupt_to_domain (const struct dt_device_node *dev, +const struct dt_irq *dt_irq, +void *data) +{ +struct domain *d = data; +bool_t need_mapping = !dt_device_for_passthrough (dev); +unsigned int irq = dt_irq->irq; +int res; + +if ( irq <NR_LOCAL_IRQS ) + { +printk (XENLOG_ERR "%s: IRQ%" PRId32" is not a SPI\n" , +dt_node_name (dev), irq); +return -EINVAL ; + } + +/* Setup the IRQ type */ + res =irq_set_spi_type (irq, dt_irq->type); +if ( res ) + { +printk (XENLOG_ERR +"%s: Unable to setup IRQ%" PRId32" to dom%d\n" , +dt_node_name (dev), irq, d->domain_id); +return res; + } + + res =irq_permit_access (d, irq); +if ( res ) + { +printk (XENLOG_ERR "Unable to permit to dom%u access to IRQ %u\n" , + d->domain_id, irq); +return res; + } + +if ( need_mapping ) + { +/* +* Checking the return of vgic_reserve_virq is not +* necessary. It should not fail except when we try to map +* the IRQ twice. This can legitimately happen if the IRQ is shared +*/ +vgic_reserve_virq (d, irq); + + res =route_irq_to_guest (d, irq, irq,dt_node_name (dev)); +if ( res <0 ) + { +printk (XENLOG_ERR "Unable to map IRQ%" PRId32" to dom%d\n" , + irq, d->domain_id); +return res; + } + } + +DPRINT (" - IRQ: %u\n" , irq); + +return 0 ; +} + +static int map_range_to_domain (const struct dt_device_node *dev, +u64 addr,u64 len, +void *data) +{ +struct domain *d = data; +int res; + + res =map_mmio_regions (d, +paddr_to_pfn (addr &PAGE_MASK ), +DIV_ROUND_UP (len,PAGE_SIZE ), +paddr_to_pfn (addr &PAGE_MASK )); +if ( res <0 ) + { +printk (XENLOG_ERR "Unable to map 0x%" PRIx64 +" - 0x%" PRIx64" in domain %d\n" , + addr &PAGE_MASK ,PAGE_ALIGN (addr + len) -1 , + d->domain_id); +return res; + } + +DPRINT (" - MMIO: %010" PRIx64" - %010" PRIx64"\n" , addr, addr + len); + +return 0 ; +} + +/* +* For a node which describes a discoverable bus (such as a PCI bus) +* then we may need to perform additional mappings in order to make +* the child resources available to domain 0. +*/ +static int map_device_children (struct domain *d, +const struct dt_device_node *dev) +{ +bool_t need_mapping = !dt_device_for_passthrough (dev); +int ret; + +if (dt_device_type_is_equal (dev,"pci" ) ) + { +DPRINT ("Mapping children of %s to guest\n" ,dt_node_full_name (dev)); + +/* +* We need to handle IRQs even if !need_mapping in order to +* setup the domain's permissions on the device's IRQs, such +* that it can pass them through to other domains. +*/ + ret =dt_for_each_irq_map (dev, &map_interrupt_to_domain, d); +if ( ret <0 ) +return ret; + +if ( need_mapping ) + { + ret =dt_for_each_range (dev, &map_range_to_domain, d); +if ( ret <0 ) +return ret; + } + } + +return 0 ; +} +/* * For a given device node: * - Give permission to the guest to manage IRQ and MMIO range
@@ -1074,6 +1191,10 @@ static int handle_device(struct domain *d, struct dt_device_node *dev) } } + res =map_device_children (d, dev); +if ( res ) +return res; +return 0 ; }
xen/arch/arm/platforms/xgene-storm.c +0 -143
155 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Re: [PATCH v4 5/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
Hi Ian,
NIT in the title: The final point is not necessary
Quoted 11 lines · Ian Campbell
xen/arch/arm/domain_build.c +11
-0+static int map_device_children (struct domain *d, +const struct dt_device_node *dev) +{ +bool_t need_mapping = !dt_device_for_passthrough (dev); +int ret; + +if (dt_device_type_is_equal (dev,"pci" ) ) + { +DPRINT ("Mapping children of %s to guest\n" ,dt_node_full_name (dev)); + +/*
xen/arch/arm/domain_build.c static int make_timer_node(const struct domain *d, void *fdt, · line 1045
Quoted 10 lines
xen/arch/arm/domain_build.c +10
-0+* We need to handle IRQs even if !need_mapping in order to +* setup the domain's permissions on the device's IRQs, such +* that it can pass them through to other domains. +*/ + ret =dt_for_each_irq_map (dev, &map_interrupt_to_domain, d); +if ( ret <0 ) +return ret; + +if ( need_mapping ) + {
I forgot to mention in the previous version that we need to give iomem permission to the guest. Otherwise DOM0 won't be able to map the BAR into the guest.
Regards,
Signature · 1 line
Julien Grall
Re: [PATCH v4 5/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
Quoted 22 lines · Julien Grall
Hi Ian,
NIT in the title: The final point is not necessary
Quoted 17 lines · Ian Campbell
xen/arch/arm/domain_build.c +17
-0+static int map_device_children (struct domain *d, +const struct dt_device_node *dev) +{ +bool_t need_mapping = !dt_device_for_passthrough (dev); +int ret; + +if (dt_device_type_is_equal (dev,"pci" ) ) + { +DPRINT ("Mapping children of %s to guest\n" ,dt_node_full_name (dev)); + +/* +* We need to handle IRQs even if !need_mapping in order to +* setup the domain's permissions on the device's IRQs, such +* that it can pass them through to other domains. +*/ + ret =dt_for_each_irq_map (dev, &map_interrupt_to_domain, d); +if ( ret <0 )
Quoted 8 lines
xen/arch/arm/domain_build.c static int make_timer_node(const struct domain *d, void *fdt, · line 1045
Quoted 4 lines
xen/arch/arm/domain_build.c +4
-0+return ret; + +if ( need_mapping ) + {I forgot to mention in the previous version that we need to give iomem permission to the guest. Otherwise DOM0 won't be able to map the BAR into the guest.
This boils down to a call to iomem_permit_access in the map_range_to_domain callback and moving the need_mapping check down into the cb surrouding only the map_mmio_region call but not the permis_access one, right?
Re: [PATCH v4 5/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
Hi Ian,
Quoted 9 lines · Ian Campbell
Quoted 3 lines · Julien Grall
I forgot to mention in the previous version that we need to give iomem permission to the guest. Otherwise DOM0 won't be able to map the BAR into the guest.
This boils down to a call to
iomem_permit_accessin themap_range_to_domaincallback and moving theneed_mappingcheck down into the cb surrouding only themap_mmio_regioncall but not thepermis_accessone, right?
Correct.
Regards,
Signature · 1 line
Julien Grall
PATCH v4 6/6 xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
In reply to Ian CampbellThis provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
Functions/types renamed and reindented (because apparently we do that for these).
Needs a selection of IORESOURCE_* defines, which I've taken from Linux and have included locally for now until we figure out where else they might be needed.
---
v3: New patch
--- xen/common/device_tree.c | 108 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-)
xen/common/device_tree.c +105 -3
@@ -399,6 +399,26 @@ int dt_n_size_cells(const struct dt_device_node *np) }/* +* These are defined in Linux where much of this code comes from, but +* are currently unused outside this file in the context of Xen. +*/ +#define IORESOURCE_BITS 0x000000ff/* Bus-specific bits */ + +#define IORESOURCE_TYPE_BITS 0x00001f00/* Resource type */ +#define IORESOURCE_IO 0x00000100/* PCI/ISA I/O ports */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_REG 0x00000300/* Register offsets */ +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 +#define IORESOURCE_BUS 0x00001000 + +#define IORESOURCE_PREFETCH 0x00002000/* No side effects */ +#define IORESOURCE_READONLY 0x00004000 +#define IORESOURCE_CACHEABLE 0x00008000 +#define IORESOURCE_RANGELENGTH 0x00010000 +#define IORESOURCE_SHADOWABLE 0x00020000 + +/* * Default translator (generic bus) */ static bool_t dt_bus_default_match (const struct dt_device_node *node)
@@ -462,9 +482,81 @@ static int dt_bus_default_translate(__be32 *addr, u64 offset, int na) }static unsigned int dt_bus_default_get_flags (const __be32 *addr) { -/* TODO: Return the type of memory (device, ...) for caching -* attribute during mapping */ -return 0 ; +return IORESOURCE_MEM ; +} + +/* +* PCI bus specific translator +*/ + +static bool_t dt_bus_pci_match (const struct dt_device_node *np) +{ +/* +* "pciex" is PCI Express "vci" is for the /chaos bridge on 1st-gen PCI +* powermacs "ht" is hypertransport +*/ +return !strcmp (np->type,"pci" ) || !strcmp (np->type,"pciex" ) || + !strcmp (np->type,"vci" ) || !strcmp (np->type,"ht" ); +} + +static void dt_bus_pci_count_cells (const struct dt_device_node *np, +int *addrc,int *sizec) +{ +if (addrc) + *addrc =3 ; +if (sizec) + *sizec =2 ; +} + +static unsigned int dt_bus_pci_get_flags (const __be32 *addr) +{ +unsigned int flags =0 ; +u32 w =be32_to_cpup (addr); + +switch ((w >>24 ) &0x03 ) { +case 0x01 : + flags |=IORESOURCE_IO ; +break ; +case 0x02 :/* 32 bits */ +case 0x03 :/* 64 bits */ + flags |=IORESOURCE_MEM ; +break ; + } +if (w &0x40000000 ) + flags |=IORESOURCE_PREFETCH ; +return flags; +} + +static u64 dt_bus_pci_map (__be32 *addr,const __be32 *range,int na,int ns, +int pna) +{ +u64 cp, s, da; +unsigned int af, rf; + + af =dt_bus_pci_get_flags (addr); + rf =dt_bus_pci_get_flags (range); + +/* Check address type match */ +if ((af ^ rf) & (IORESOURCE_MEM |IORESOURCE_IO )) +return DT_BAD_ADDR ; + +/* Read address values, skipping high cell */ + cp =dt_read_number (range +1 , na -1 ); + s =dt_read_number (range + na + pna, ns); + da =dt_read_number (addr +1 , na -1 ); + +dt_dprintk ("DT: PCI map, cp=%llx, s=%llx, da=%llx\n" , + (unsigned long long )cp, (unsigned long long )s, + (unsigned long long )da); + +if (da < cp || da >= (cp + s)) +return DT_BAD_ADDR ; +return da - cp; +} + +static int dt_bus_pci_translate (__be32 *addr,u64 offset,int na) +{ +return dt_bus_default_translate (addr +1 , offset, na -1 ); }/*
@@ -472,6 +564,16 @@ static unsigned int dt_bus_default_get_flags(const __be32 *addr)*/ static const struct dt_bus dt_busses[] = { +/* PCI */ + { + .name ="pci" , + .addresses ="assigned-addresses" , + .match = dt_bus_pci_match, + .count_cells = dt_bus_pci_count_cells, + .map = dt_bus_pci_map, + .translate = dt_bus_pci_translate, + .get_flags = dt_bus_pci_get_flags, + },/* Default */ { .name ="default" ,
Signature · 1 line
1.7.10.4
Re: [PATCH v4 6/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
Hi Ian,
Quoted 3 lines · Ian Campbell
This provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
I though the previous patch (#5) was enough to handle PCI. May I ask why we need it?
Quoted 2 lines
Functions/types renamed and reindented (because apparently we do that for these).
My mistake, when I first port the functions from Linux I changed the name and the coding style to match the existent functions in xen/common/device_tree.c
All the functions to work directly on the DT blob have been moved in a separate file (arch/arm/bootfdt.c), so this file is mostly Linux code. I'm thinking to resync it correctly for Xen 4.7.
Quoted 3 lines
Needs a selection of IORESOURCE_* defines, which I've taken from Linux and have included locally for now until we figure out where else they might be needed.
Regards,
Signature · 1 line
Julien Grall
Re: [PATCH v4 6/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
Quoted 9 lines · Julien Grall
Hi Ian,
Quoted 3 lines · Ian Campbell
This provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
I though the previous patch (#5) was enough to handle PCI. May I ask why we need it?
There are some subtle differences in how the generic code vs. the pci specific code here will handle buggy DTs (i.e. #*-cells which are not as required by the pci bindings). This will mean we tolerate such device trees better.
I say "buggy", but actually it's not clear to me from reading "PCI Bus Binding to Open Firmware" that when the device_type is "pci" that #*-cells shouldn't be assumed to have the values given in that text, e.g. the text says "The value of "#address-cells" for PCI Bus Nodes is 3." and not "A PCI Bus Node must contain a #address-cells property containing 3". Maybe that interpretation is bogus, but with this patch we are are able to cope with DTs written by people who do read it like that.
FWIW it also gets us the ability to parse the flags (cacheability), although at the moment we only check them for validity rather than use them.
Quoted 10 lines
Quoted 2 lines
Functions/types renamed and reindented (because apparently we do that for these).
My mistake, when I first port the functions from Linux I changed the name and the coding style to match the existent functions in
xen/common/device_tree.cAll the functions to work directly on the DT blob have been moved in a separate file (
arch/arm/bootfdt.c), so this file is mostly Linux code. I'm thinking to resync it correctly for Xen 4.7.
That sounds good, thanks.
Quoted 7 lines
Quoted 4 lines
Needs a selection of IORESOURCE_* defines, which I've taken from Linux and have included locally for now until we figure out where else they might be needed.
Regards,
Re: [PATCH v4 6/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
Quoted 25 lines · Ian Campbell
Quoted 9 lines · Julien Grall
Hi Ian,
Quoted 3 lines · Ian Campbell
This provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
I though the previous patch (#5) was enough to handle PCI. May I ask why we need it?
There are some subtle differences in how the generic code vs. the pci specific code here will handle buggy DTs (i.e. #*-cells which are not as required by the pci bindings). This will mean we tolerate such device trees better.
I say "buggy", but actually it's not clear to me from reading "PCI Bus Binding to Open Firmware" that when the
device_typeis "pci" that #*-cells shouldn't be assumed to have the values given in that text, e.g. the text says "The value of "#address-cells" for PCI Bus Nodes is 3." and not "A PCI Bus Node must contain a #address-cells property containing 3". Maybe that interpretation is bogus, but with this patch we are are able to cope with DTs written by people who do read it like that.
Quoted 3 lines
FWIW it also gets us the ability to parse the flags (cacheability), although at the moment we only check them for validity rather than use them.
I've pasted a slightly adjusted version of this into the commit message for v5.
Quoted 28 lines
Quoted 11 lines
Quoted 3 lines
Functions/types renamed and reindented (because apparently we do that for these).
My mistake, when I first port the functions from Linux I changed the name and the coding style to match the existent functions in
xen/common/device_tree.cAll the functions to work directly on the DT blob have been moved in a separate file (
arch/arm/bootfdt.c), so this file is mostly Linux code. I'm thinking to resync it correctly for Xen 4.7.That sounds good, thanks.
Quoted 7 lines
Quoted 4 lines
Needs a selection of IORESOURCE_* defines, which I've taken from Linux and have included locally for now until we figure out where else they might be needed.
Regards,
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
Re: [PATCH v4 6/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
Quoted 17 lines · Ian Campbell
Quoted 16 lines · Ian Campbell
Quoted 9 lines · Julien Grall
Hi Ian,
Quoted 3 lines · Ian Campbell
This provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
I though the previous patch (#5) was enough to handle PCI. May I ask why we need it?
There are some subtle differences in how the generic code vs. the pci specific code here will handle buggy DTs (i.e. #*-cells which are not as required by the pci bindings). This will mean we tolerate such device trees better.
Quoted 8 lines
Quoted 8 lines
I say "buggy", but actually it's not clear to me from reading "PCI Bus Binding to Open Firmware" that when the
device_typeis "pci" that #*-cells shouldn't be assumed to have the values given in that text, e.g. the text says "The value of "#address-cells" for PCI Bus Nodes is 3." and not "A PCI Bus Node must contain a #address-cells property containing 3". Maybe that interpretation is bogus, but with this patch we are are able to cope with DTs written by people who do read it like that.
If the #address-cells and #size-cells are not correct that will likely means that the property "reg" in the PCI node would be misinterpreted by Xen.
I think it's here to cope with DT when #*-cells are not specified. The spec doesn't say if the properties should be present or not.
Quoted 3 lines
Quoted 3 lines
FWIW it also gets us the ability to parse the flags (cacheability), although at the moment we only check them for validity rather than use them.
Good point.
Quoted 2 lines
I've pasted a slightly adjusted version of this into the commit message for v5.
Thank you!
Regards,
Signature · 1 line
Julien Grall
Re: [PATCH v4 6/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry)
Quoted 27 lines · Julien Grall
Quoted 17 lines · Ian Campbell
Quoted 16 lines · Ian Campbell
Quoted 9 lines · Julien Grall
Hi Ian,
Quoted 3 lines · Ian Campbell
This provides specific handlers for the PCI bus relating to matching and translating. It's mostly similar to the defaults but includes some additional error checks and other PCI specific bits.
I though the previous patch (#5) was enough to handle PCI. May I ask why we need it?
There are some subtle differences in how the generic code vs. the pci specific code here will handle buggy DTs (i.e. #*-cells which are not as required by the pci bindings). This will mean we tolerate such device trees better.
Quoted 8 lines
Quoted 8 lines
I say "buggy", but actually it's not clear to me from reading "PCI Bus Binding to Open Firmware" that when the
device_typeis "pci" that #*-cells shouldn't be assumed to have the values given in that text, e.g. the text says "The value of "#address-cells" for PCI Bus Nodes is 3." and not "A PCI Bus Node must contain a #address-cells property containing 3". Maybe that interpretation is bogus, but with this patch we are are able to cope with DTs written by people who do read it like that.
Quoted 3 lines
If the #address-cells and #size-cells are not correct that will likely means that the property "reg" in the PCI node would be misinterpreted by Xen.
Right, everything falls apart in that case anyway, unless the #*-cells properties are inconsistent with a regs which correctly follows the spec, but that's the most unlikely case I think.
Quoted 2 lines
I think it's here to cope with DT when #*-cells are not specified. The spec doesn't say if the properties should be present or not.
Right.
On Fri, 2015-05-08 at 12:26 +0100, Ian Campbell wrote:
Sigh, I seem to be making a habbit of not updating the subject of my 0/N mails at the minute. This is v4 as the patches themselves claim.
Quoted 28 lines
This series adds parsing of the DT ranges and interrupt-map properties for PCI devices, these contain the MMIOs and IRQs used by children on the bus. This replaces the specific mapping stuff on xgene.
Since last time I've made the irq iterator pass a translated IRQ to the callback and (hopefully) arranged to handle devices which have been reserved for passthrough somewhat correctly.
Ian.
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel