[PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06

Gabriele Paoloni gabriele.paoloni at huawei.com
Fri Nov 25 08:27:40 PST 2016


Hi Arnd

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: 25 November 2016 12:04
> To: Gabriele Paoloni
> Cc: linux-arm-kernel at lists.infradead.org; mark.rutland at arm.com;
> catalin.marinas at arm.com; linux-pci at vger.kernel.org;
> liviu.dudau at arm.com; Linuxarm; lorenzo.pieralisi at arm.com; xuwei (O);
> Jason Gunthorpe; T homas Petazzoni; linux-serial at vger.kernel.org;
> benh at kernel.crashing.org; devicetree at vger.kernel.org; minyard at acm.org;
> will.deacon at arm.com; John Garry; olof at lixom.net; robh+dt at kernel.org;
> bhelgaas at go og le.com; kantyzc at 163.com; zhichang.yuan 02 at gmail.com;
> linux-kernel at vger.kernel.org; Yuanzhichang; zourongrong at gmail.com
> Subject: Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on
> Hip06
> 
> On Friday, November 25, 2016 8:46:11 AM CET Gabriele Paoloni wrote:
> > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > >
> > > On Wednesday, November 23, 2016 6:07:11 PM CET Arnd Bergmann wrote:
> > > > On Wednesday, November 23, 2016 3:22:33 PM CET Gabriele Paoloni
> > > wrote:
> > > > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > > > > > On Friday, November 18, 2016 5:03:11 PM CET Gabriele Paoloni
> > >  /*
> > > @@ -549,9 +548,14 @@ static int of_translate_one(struct device_node
> > > *parent, struct of_bus *bus,
> > >   * that translation is impossible (that is we are not dealing with
> a
> > > value
> > >   * that can be mapped to a cpu physical address). This is not
> really
> > > specified
> > >   * that way, but this is traditionally the way IBM at least do
> things
> > > + *
> > > + * Whenever the translation fails, the *host pointer will be set
> to
> > > the
> > > + * device that lacks a tranlation, and the return code is relative
> to
> > > + * that node.
> >
> > This seems to be wrong to me. We are abusing of the error conditions.
> > So effectively if there is a buggy DT for an IO resource we end up
> > assuming that we are using a special IO device with unmapped
> addresses.
> >
> > The patch at the bottom apply on top of this one and I think is a
> more
> > reasonable approach
> 
> It was meant as a logical extension to the existing interface,
> translating the address as far as we can, and reporting back
> how far we got.
> 
> Maybe we can return 'of_root' by instead of NULL to signify
> that we have converted all the way to the root of the DT?
> That would make it more consistent, but slightly more complicated
> for the common case.

Mmm not sure really...the point is that now the **host parameter is
used both as a flag and also in of_translate_ioport...the problem
that I see is where we set the "host" parameter...I have a proposal
below...

[...]

> pci_bus_alloc_resource(struct
> > > pci_bus *bus,
> > >  			void *alignf_data);
> 
> [Many lines of reply trimmed here, please make sure you don't quote too
> much context when you reply, it's really annoying to read through
> it otherwise]

Sorry! I'll take care of this in the future...

> 
> >  /*
> > + * of_isa_indirect_io - get the IO address from some isa reg
> property value.
> > + *	For some isa/lpc devices, no ranges property in ancestor node.
> > + *	The device addresses are described directly in their regs
> property.
> > + *	This fixup function will be called to get the IO address of
> isa/lpc
> > + *	devices when the normal of_translation failed.
> > + *
> > + * @parent:	points to the parent dts node;
> > + * @bus:		points to the of_bus which can be used to parse
> address;
> > + * @addr:	the address from reg property;
> > + * @na:		the address cell counter of @addr;
> > + * @presult:	store the address paresed from @addr;
> > + *
> > + * return 1 when successfully get the I/O address;
> > + * 0 will return for some failures.
> > + */
> > +static int of_get_isa_indirect_io(struct device_node *parent,
> > +				struct of_bus *bus, __be32 *addr,
> > +				int na, u64 *presult)
> > +{
> > +	unsigned int flags;
> > +	unsigned int rlen;
> > +
> > +	/* whether support indirectIO */
> > +	if (!indirect_io_enabled())
> > +		return 0;
> > +
> > +	if (!of_bus_isa_match(parent))
> > +		return 0;
> > +
> > +	flags = bus->get_flags(addr);
> > +	if (!(flags & IORESOURCE_IO))
> > +		return 0;
> > +
> > +	/* there is ranges property, apply the normal translation
> directly. */
> > +	if (of_get_property(parent, "ranges", &rlen))
> > +		return 0;
> > +
> > +	*presult = of_read_number(addr + 1, na - 1);
> > +	/* this fixup is only valid for specific I/O range. */
> > +	return addr_is_indirect_io(*presult);
> > +}
> 
> Right, this would work. The reason I didn't go down this route is
> that I wanted to keep it generic enough to allow doing the same
> for PCI host bridges with a nonlinear mapping of the I/O space.
> 
> There isn't really anything special about ISA here, other than the
> fact that the one driver that needs it happens to be for ISA rather
> than PCI.

Yes I see your point please consider the patch at the bottom...

> 
> > +/*
> >   * Translate an address from the device-tree into a CPU physical
> address,
> >   * this walks up the tree and applies the various bus mappings on
> the
> >   * way.
> > @@ -600,14 +643,23 @@ static u64 __of_translate_address(struct
> device_node *dev,
> >  			result = of_read_number(addr, na);
> >  			break;
> >  		}
> > +		/*
> > +		 * For indirectIO device which has no ranges property, get
> > +		 * the address from reg directly.
> > +		 */
> > +		if (of_get_isa_indirect_io(dev, bus, addr, na, &result)) {
> > +			pr_debug("isa indirectIO matched(%s)..addr =
> 0x%llx\n",
> > +				of_node_full_name(dev), result);
> > +			*host = of_node_get(parent);
> > +			break;
> > +		}
> >
> 
> If we do the special case for ISA as you suggest above, I would still
> want
> to keep it in of_translate_ioport(), I think that's a useful change by
> itself in my patch.

This comes without saying...the patch I proposed here already applied on
top of your changes and, in fact, you can see that I set 
"*host = of_node_get(parent);" above in my patch to be used by 
of_translate_ioport()
 
> 
> 	Arnde
> 
> 
> 

Below I have reworked my patch (that still applies on top of your one) to
make it not ISA specific.
Notice that of_translate_ioport() still stands and that in addr_is_indirect_io()
we make sure the bus address to be in the bus address range that the special
host operates on...

---
 drivers/of/address.c       | 56 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/of_address.h | 17 ++++++++++++++
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 5decaba..2b34931 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -540,6 +540,48 @@ static u64 of_translate_one(struct device_node *parent, struct of_bus *bus,
 }
 
 /*
+ * of_get_indirect_io - get the IO address from some reg property value.
+ *	For some special host devices, we have no ranges property node and
+ *	we directly use the bus addresses of the children regs property.
+ *	This fixup function will be called to get the IO address of isa/lpc
+ *	devices when the normal of_translation failed.
+ *
+ * @parent:	points to the parent dts node;
+ * @bus:		points to the of_bus which can be used to parse address;
+ * @addr:	the address from reg property;
+ * @na:		the address cell counter of @addr;
+ * @presult:	store the address parsed from @addr;
+ *
+ * return 1 when successfully get the I/O address;
+ * 0 will return for some failures.
+ */
+static int of_get_indirect_io(struct device_node *parent,
+				struct of_bus *bus, __be32 *addr,
+				int na, u64 *presult)
+{
+	unsigned int flags;
+	unsigned int rlen;
+
+	/* whether support indirectIO */
+	if (!indirect_io_enabled())
+		return 0;
+
+	flags = bus->get_flags(addr);
+	if (!(flags & IORESOURCE_IO))
+		return 0;
+
+	/* there is ranges property, apply the normal translation directly. */
+	if (of_get_property(parent, "ranges", &rlen))
+		return 0;
+
+	*presult = of_read_number(addr + 1, na - 1);
+
+	/* check if the bus address falls into the range of
+	 * the special host device*/
+	return addr_is_indirect_io(*presult);
+}
+
+/*
  * Translate an address from the device-tree into a CPU physical address,
  * this walks up the tree and applies the various bus mappings on the
  * way.
@@ -601,13 +643,23 @@ static u64 __of_translate_address(struct device_node *dev,
 			break;
 		}
 
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		if (of_get_indirect_io(dev, bus, addr, na, &result)) {
+			pr_debug("isa indirectIO matched(%s)..addr = 0x%llx\n",
+				of_node_full_name(dev), result);
+			*host = of_node_get(parent);
+			break;
+		}
+
 		/* Get new parent bus and counts */
 		pbus = of_match_bus(parent);
 		pbus->count_cells(dev, &pna, &pns);
 		if (!OF_CHECK_COUNTS(pna, pns)) {
-			pr_debug("Bad cell count for %s\n",
+			pr_err("Bad cell count for %s\n",
 				 of_node_full_name(dev));
-			*host = of_node_get(parent);
 			break;
 		}
 
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3786473..14848d8 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -24,6 +24,23 @@ struct of_pci_range {
 #define for_each_of_pci_range(parser, range) \
 	for (; of_pci_range_parser_one(parser, range);)
 
+#ifndef indirect_io_enabled
+#define indirect_io_enabled indirect_io_enabled
+static inline bool indirect_io_enabled(void)
+{
+	return false;
+}
+#endif
+
+#ifndef addr_is_indirect_io
+#define addr_is_indirect_io addr_is_indirect_io
+static inline int addr_is_indirect_io(u64 taddr)
+{
+	return 0;
+}
+#endif
+
+
 /* Translate a DMA address from device space to CPU space */
 extern u64 of_translate_dma_address(struct device_node *dev,
 				    const __be32 *in_addr);
-- 
2.7.4






More information about the linux-arm-kernel mailing list