Re: [U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-08-04 Thread Thierry Reding
On Sun, Aug 02, 2015 at 03:27:53PM -0600, Simon Glass wrote:
 Hi,
 
 On 27 July 2015 at 11:13, Simon Glass s...@chromium.org wrote:
  Hi,
 
  On 23 July 2015 at 10:51, Stephen Warren swar...@wwwdotorg.org wrote:
  From: Thierry Reding tred...@nvidia.com
 
  Signed-off-by: Thierry Reding tred...@nvidia.com
  Signed-off-by: Tom Warren twar...@nvidia.com
  Signed-off-by: Stephen Warren swar...@nvidia.com
  ---
  Simon,
 
  When Thierry first posted this patch, you responded:
 
   +   parent = fdt_parent_offset(blob, node);
 
  This function is very slow as it must scan the whole tree. Can we
  instead pass in the parent node?
 
  I don't think that's possible in general. This function is called from
  fdtdec_get_addr(), and it's easy to find call sites of that function that
  don't have the parent node available. IIRC, the first couple of example I
  found scan the DT for a node with a certain compatible value, or look up
  nodes via aliases, rather than being called while parsing the DT in a
  top-down tree-like fashion, where the parent node is easily available. I
  didn't do an exhaustive search after I found a few problematic cases.
 
  Also, how about (in addition) a
  version of this function that works for devices? Like:
 
  device_get_addr_size(struct udevice *dev, ...)
 
  so that it can handle this for you.
 
  That sounds like a separate patch?
 
  Yes, but I think we should get it in there so that people don't start
  using this (wildly inefficient) function when they don't need to. I
  think by passing in the parent node we force people to think about the
  cost.
 
  Yes the driver model function can be a separate patch, but let's get
  it in at about the same time. We have dev_get_addr() so could have
  dev_get_addr_size().
 
 
  Equally, I see that struct udevice contains an of_offset field, but no
  parent_of_offset or similar. There is a struct udevice *parent though;
  is the struct udevice hierarchy guaranteed to 100% match the DT
  hierarchy? I know this isn't necessarily guaranteed in Linux's device
  model for example.
 
  Yes it is 100% guaranteed, so dev-parent-of_offset will do the right 
  thing.
 
 
  As such, this patch seems OK to me as-is.
  ---
   lib/fdtdec.c | 56 
   1 file changed, 36 insertions(+), 20 deletions(-)
 
 
 This patch has been applied. I'm going to post a revert of this patch.
 Please can you take a look at the comments above? In particular this
 function is called from dev_get_addr() which is a core driver model
 function. It needs to be fast - and in fact dev_get_addr() already has
 access to the parent node.

Perhaps this could be fixed by doing passing in the parent as an
optional argument and then do something like this:

if (parent  0) {
parent = fdt_parent_offset(blob, node);
if (parent  0) {
...
}
}

In that case callers that have access to the parent node already can
pass it in, but others can simply pass in -1 and have the function do
the lookup.

 Also looking a bit closer this patch does a lot more than 'fix it for
 64-bit'. A commit message would be useful to explain what problems it
 is fixing, etc.
 
 Another point is that fdt_addr_t and fdt_size_t are supposed to match
 the address size used in the device tree. Is that not the case with
 Tegra210?

You can't assume that #address-cells and #size-cells will be 2 for all
64-bit platforms. Some may well go with #address-cells = 1 and #size-
cells = 1, and I've seen others do #address-cells = 2 and #size-cells =
1. All of these combinations are perfectly valid.

As such, fdt_addr_t and fdt_size_t make sense only if they are the
maximum that the architecture can support. Even so an address could
technically be larger than that, if it's behind a translated bus, for
example.

So what this does is really fix parsing of address and size cells in the
general case, though it would still fail for values of #address-cells or
#size-cells bigger than 2 (because we don't have a datatype that would
be able to contain such large values).

Note that there's also still a corner case that this doesn't handle. The
DT specification states, if I remember correctly, that #address-cells
and #size-cells are inherited. That means with the current code we will
wrongly parse something like this:

/ {
...
#address-cells = 1;
#size-cells = 1;
...
bus@ {
...
device@ {
...
reg = 0x 0x1000;
...
};
...
};
...
};

According to the DT specification the bus@ node would inherit
#address-cells = 1 and #size-cells = 1 from the root node. However

Re: [U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-08-04 Thread Stephen Warren

On 08/04/2015 08:26 AM, Thierry Reding wrote:
... [ discussion of new fdtdec_get_addr_size() implementation]

So what this does is really fix parsing of address and size cells in the
general case, though it would still fail for values of #address-cells or
#size-cells bigger than 2 (because we don't have a datatype that would
be able to contain such large values).

Note that there's also still a corner case that this doesn't handle. The
DT specification states, if I remember correctly, that #address-cells
and #size-cells are inherited. That means with the current code we will
wrongly parse something like this:

/ {
...
#address-cells = 1;
#size-cells = 1;
...
bus@ {
...
device@ {
...
reg = 0x 0x1000;
...
};
...
};
...
};

According to the DT specification the bus@ node would inherit
#address-cells = 1 and #size-cells = 1 from the root node. However
with libfdt what really happens is that since bus@ does not have
either property it will default to 2 in both cases. I'm not sure if this
really is a problem. Typically nodes are not nested that deeply, or if
they are then, typically, they explicitly contain #address-cells and
#size-cells properties.


I don't think #address-cells/#size-cells do actually get inherited. 
Admittedly some other properties (e.g. interrupt-parent) do, but 
according to:


https://lists.ozlabs.org/pipermail/linuxppc-dev/2008-January/049113.html
[PATCH] powerpc: #address-cells  #size-cells properties not inherited

... and my vague memory, these two don't.

You can search Google for e.g. #address-cells inherited and find a 
number of similar assertions.


___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-08-04 Thread Thierry Reding
On Tue, Aug 04, 2015 at 09:23:27AM -0600, Stephen Warren wrote:
 On 08/04/2015 08:26 AM, Thierry Reding wrote:
 ... [ discussion of new fdtdec_get_addr_size() implementation]
 So what this does is really fix parsing of address and size cells in the
 general case, though it would still fail for values of #address-cells or
 #size-cells bigger than 2 (because we don't have a datatype that would
 be able to contain such large values).
 
 Note that there's also still a corner case that this doesn't handle. The
 DT specification states, if I remember correctly, that #address-cells
 and #size-cells are inherited. That means with the current code we will
 wrongly parse something like this:
 
  / {
  ...
  #address-cells = 1;
  #size-cells = 1;
  ...
  bus@ {
  ...
  device@ {
  ...
  reg = 0x 0x1000;
  ...
  };
  ...
  };
  ...
  };
 
 According to the DT specification the bus@ node would inherit
 #address-cells = 1 and #size-cells = 1 from the root node. However
 with libfdt what really happens is that since bus@ does not have
 either property it will default to 2 in both cases. I'm not sure if this
 really is a problem. Typically nodes are not nested that deeply, or if
 they are then, typically, they explicitly contain #address-cells and
 #size-cells properties.
 
 I don't think #address-cells/#size-cells do actually get inherited.
 Admittedly some other properties (e.g. interrupt-parent) do, but according
 to:
 
 https://lists.ozlabs.org/pipermail/linuxppc-dev/2008-January/049113.html
 [PATCH] powerpc: #address-cells  #size-cells properties not inherited
 
 ... and my vague memory, these two don't.
 
 You can search Google for e.g. #address-cells inherited and find a number
 of similar assertions.

Okay, that's good. It means there's not even a corner case. =)

Thierry


signature.asc
Description: PGP signature
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-08-02 Thread Simon Glass
Hi,

On 27 July 2015 at 11:13, Simon Glass s...@chromium.org wrote:
 Hi,

 On 23 July 2015 at 10:51, Stephen Warren swar...@wwwdotorg.org wrote:
 From: Thierry Reding tred...@nvidia.com

 Signed-off-by: Thierry Reding tred...@nvidia.com
 Signed-off-by: Tom Warren twar...@nvidia.com
 Signed-off-by: Stephen Warren swar...@nvidia.com
 ---
 Simon,

 When Thierry first posted this patch, you responded:

  +   parent = fdt_parent_offset(blob, node);

 This function is very slow as it must scan the whole tree. Can we
 instead pass in the parent node?

 I don't think that's possible in general. This function is called from
 fdtdec_get_addr(), and it's easy to find call sites of that function that
 don't have the parent node available. IIRC, the first couple of example I
 found scan the DT for a node with a certain compatible value, or look up
 nodes via aliases, rather than being called while parsing the DT in a
 top-down tree-like fashion, where the parent node is easily available. I
 didn't do an exhaustive search after I found a few problematic cases.

 Also, how about (in addition) a
 version of this function that works for devices? Like:

 device_get_addr_size(struct udevice *dev, ...)

 so that it can handle this for you.

 That sounds like a separate patch?

 Yes, but I think we should get it in there so that people don't start
 using this (wildly inefficient) function when they don't need to. I
 think by passing in the parent node we force people to think about the
 cost.

 Yes the driver model function can be a separate patch, but let's get
 it in at about the same time. We have dev_get_addr() so could have
 dev_get_addr_size().


 Equally, I see that struct udevice contains an of_offset field, but no
 parent_of_offset or similar. There is a struct udevice *parent though;
 is the struct udevice hierarchy guaranteed to 100% match the DT
 hierarchy? I know this isn't necessarily guaranteed in Linux's device
 model for example.

 Yes it is 100% guaranteed, so dev-parent-of_offset will do the right thing.


 As such, this patch seems OK to me as-is.
 ---
  lib/fdtdec.c | 56 
  1 file changed, 36 insertions(+), 20 deletions(-)


This patch has been applied. I'm going to post a revert of this patch.
Please can you take a look at the comments above? In particular this
function is called from dev_get_addr() which is a core driver model
function. It needs to be fast - and in fact dev_get_addr() already has
access to the parent node.

Also looking a bit closer this patch does a lot more than 'fix it for
64-bit'. A commit message would be useful to explain what problems it
is fixing, etc.

Another point is that fdt_addr_t and fdt_size_t are supposed to match
the address size used in the device tree. Is that not the case with
Tegra210?

 diff --git a/lib/fdtdec.c b/lib/fdtdec.c
 index 9c6b3619da24..56e72eafaade 100644
 --- a/lib/fdtdec.c
 +++ b/lib/fdtdec.c
 @@ -88,29 +88,45 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
  fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
 const char *prop_name, fdt_size_t *sizep)
  {
 -   const fdt_addr_t *cell;
 -   int len;
 +   const fdt32_t *ptr, *end;
 +   int parent, na, ns, len;
 +   fdt_addr_t addr;

 debug(%s: %s: , __func__, prop_name);
 -   cell = fdt_getprop(blob, node, prop_name, len);
 -   if (cell  ((!sizep  len == sizeof(fdt_addr_t)) ||
 -len == sizeof(fdt_addr_t) * 2)) {
 -   fdt_addr_t addr = fdt_addr_to_cpu(*cell);
 -   if (sizep) {
 -   const fdt_size_t *size;
 -
 -   size = (fdt_size_t *)((char *)cell +
 -   sizeof(fdt_addr_t));
 -   *sizep = fdt_size_to_cpu(*size);
 -   debug(addr=%08lx, size=%llx\n,
 - (ulong)addr, (u64)*sizep);
 -   } else {
 -   debug(%08lx\n, (ulong)addr);
 -   }
 -   return addr;
 +
 +   parent = fdt_parent_offset(blob, node);
 +   if (parent  0) {
 +   debug((no parent found)\n);
 +   return FDT_ADDR_T_NONE;
 }
 -   debug((not found)\n);
 -   return FDT_ADDR_T_NONE;
 +
 +   na = fdt_address_cells(blob, parent);
 +   ns = fdt_size_cells(blob, parent);
 +
 +   ptr = fdt_getprop(blob, node, prop_name, len);
 +   if (!ptr) {
 +   debug((not found)\n);
 +   return FDT_ADDR_T_NONE;
 +   }
 +
 +   end = ptr + len / sizeof(*ptr);
 +
 +   if (ptr + na + ns  end) {
 +   debug((not enough data: expected %d bytes, got %d bytes)\n,
 + (na + ns) * 4, len);
 +   return FDT_ADDR_T_NONE;
 +   }
 +
 +   addr = fdtdec_get_number(ptr, na);
 +
 +   if (sizep) {
 +   *sizep = fdtdec_get_number(ptr + na, ns);
 + 

Re: [U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-07-27 Thread Simon Glass
Hi,

On 23 July 2015 at 10:51, Stephen Warren swar...@wwwdotorg.org wrote:
 From: Thierry Reding tred...@nvidia.com

 Signed-off-by: Thierry Reding tred...@nvidia.com
 Signed-off-by: Tom Warren twar...@nvidia.com
 Signed-off-by: Stephen Warren swar...@nvidia.com
 ---
 Simon,

 When Thierry first posted this patch, you responded:

  +   parent = fdt_parent_offset(blob, node);

 This function is very slow as it must scan the whole tree. Can we
 instead pass in the parent node?

 I don't think that's possible in general. This function is called from
 fdtdec_get_addr(), and it's easy to find call sites of that function that
 don't have the parent node available. IIRC, the first couple of example I
 found scan the DT for a node with a certain compatible value, or look up
 nodes via aliases, rather than being called while parsing the DT in a
 top-down tree-like fashion, where the parent node is easily available. I
 didn't do an exhaustive search after I found a few problematic cases.

 Also, how about (in addition) a
 version of this function that works for devices? Like:

 device_get_addr_size(struct udevice *dev, ...)

 so that it can handle this for you.

 That sounds like a separate patch?

Yes, but I think we should get it in there so that people don't start
using this (wildly inefficient) function when they don't need to. I
think by passing in the parent node we force people to think about the
cost.

Yes the driver model function can be a separate patch, but let's get
it in at about the same time. We have dev_get_addr() so could have
dev_get_addr_size().


 Equally, I see that struct udevice contains an of_offset field, but no
 parent_of_offset or similar. There is a struct udevice *parent though;
 is the struct udevice hierarchy guaranteed to 100% match the DT
 hierarchy? I know this isn't necessarily guaranteed in Linux's device
 model for example.

Yes it is 100% guaranteed, so dev-parent-of_offset will do the right thing.


 As such, this patch seems OK to me as-is.
 ---
  lib/fdtdec.c | 56 
  1 file changed, 36 insertions(+), 20 deletions(-)

 diff --git a/lib/fdtdec.c b/lib/fdtdec.c
 index 9c6b3619da24..56e72eafaade 100644
 --- a/lib/fdtdec.c
 +++ b/lib/fdtdec.c
 @@ -88,29 +88,45 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
  fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
 const char *prop_name, fdt_size_t *sizep)
  {
 -   const fdt_addr_t *cell;
 -   int len;
 +   const fdt32_t *ptr, *end;
 +   int parent, na, ns, len;
 +   fdt_addr_t addr;

 debug(%s: %s: , __func__, prop_name);
 -   cell = fdt_getprop(blob, node, prop_name, len);
 -   if (cell  ((!sizep  len == sizeof(fdt_addr_t)) ||
 -len == sizeof(fdt_addr_t) * 2)) {
 -   fdt_addr_t addr = fdt_addr_to_cpu(*cell);
 -   if (sizep) {
 -   const fdt_size_t *size;
 -
 -   size = (fdt_size_t *)((char *)cell +
 -   sizeof(fdt_addr_t));
 -   *sizep = fdt_size_to_cpu(*size);
 -   debug(addr=%08lx, size=%llx\n,
 - (ulong)addr, (u64)*sizep);
 -   } else {
 -   debug(%08lx\n, (ulong)addr);
 -   }
 -   return addr;
 +
 +   parent = fdt_parent_offset(blob, node);
 +   if (parent  0) {
 +   debug((no parent found)\n);
 +   return FDT_ADDR_T_NONE;
 }
 -   debug((not found)\n);
 -   return FDT_ADDR_T_NONE;
 +
 +   na = fdt_address_cells(blob, parent);
 +   ns = fdt_size_cells(blob, parent);
 +
 +   ptr = fdt_getprop(blob, node, prop_name, len);
 +   if (!ptr) {
 +   debug((not found)\n);
 +   return FDT_ADDR_T_NONE;
 +   }
 +
 +   end = ptr + len / sizeof(*ptr);
 +
 +   if (ptr + na + ns  end) {
 +   debug((not enough data: expected %d bytes, got %d bytes)\n,
 + (na + ns) * 4, len);
 +   return FDT_ADDR_T_NONE;
 +   }
 +
 +   addr = fdtdec_get_number(ptr, na);
 +
 +   if (sizep) {
 +   *sizep = fdtdec_get_number(ptr + na, ns);
 +   debug(addr=%pa, size=%pa\n, addr, sizep);
 +   } else {
 +   debug(%pa\n, addr);
 +   }
 +
 +   return addr;
  }

  fdt_addr_t fdtdec_get_addr(const void *blob, int node,
 --
 1.9.1


Regards,
SImon
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


[U-Boot] [PATCH] fdt: Fix fdtdec_get_addr_size() for 64-bit

2015-07-23 Thread Stephen Warren
From: Thierry Reding tred...@nvidia.com

Signed-off-by: Thierry Reding tred...@nvidia.com
Signed-off-by: Tom Warren twar...@nvidia.com
Signed-off-by: Stephen Warren swar...@nvidia.com
---
Simon,

When Thierry first posted this patch, you responded:

  +   parent = fdt_parent_offset(blob, node);

 This function is very slow as it must scan the whole tree. Can we
 instead pass in the parent node?

I don't think that's possible in general. This function is called from
fdtdec_get_addr(), and it's easy to find call sites of that function that
don't have the parent node available. IIRC, the first couple of example I
found scan the DT for a node with a certain compatible value, or look up
nodes via aliases, rather than being called while parsing the DT in a
top-down tree-like fashion, where the parent node is easily available. I
didn't do an exhaustive search after I found a few problematic cases.

 Also, how about (in addition) a
 version of this function that works for devices? Like:

 device_get_addr_size(struct udevice *dev, ...)

 so that it can handle this for you.

That sounds like a separate patch?

Equally, I see that struct udevice contains an of_offset field, but no
parent_of_offset or similar. There is a struct udevice *parent though;
is the struct udevice hierarchy guaranteed to 100% match the DT
hierarchy? I know this isn't necessarily guaranteed in Linux's device
model for example.

As such, this patch seems OK to me as-is.
---
 lib/fdtdec.c | 56 
 1 file changed, 36 insertions(+), 20 deletions(-)

diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 9c6b3619da24..56e72eafaade 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -88,29 +88,45 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
 fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
const char *prop_name, fdt_size_t *sizep)
 {
-   const fdt_addr_t *cell;
-   int len;
+   const fdt32_t *ptr, *end;
+   int parent, na, ns, len;
+   fdt_addr_t addr;
 
debug(%s: %s: , __func__, prop_name);
-   cell = fdt_getprop(blob, node, prop_name, len);
-   if (cell  ((!sizep  len == sizeof(fdt_addr_t)) ||
-len == sizeof(fdt_addr_t) * 2)) {
-   fdt_addr_t addr = fdt_addr_to_cpu(*cell);
-   if (sizep) {
-   const fdt_size_t *size;
-
-   size = (fdt_size_t *)((char *)cell +
-   sizeof(fdt_addr_t));
-   *sizep = fdt_size_to_cpu(*size);
-   debug(addr=%08lx, size=%llx\n,
- (ulong)addr, (u64)*sizep);
-   } else {
-   debug(%08lx\n, (ulong)addr);
-   }
-   return addr;
+
+   parent = fdt_parent_offset(blob, node);
+   if (parent  0) {
+   debug((no parent found)\n);
+   return FDT_ADDR_T_NONE;
}
-   debug((not found)\n);
-   return FDT_ADDR_T_NONE;
+
+   na = fdt_address_cells(blob, parent);
+   ns = fdt_size_cells(blob, parent);
+
+   ptr = fdt_getprop(blob, node, prop_name, len);
+   if (!ptr) {
+   debug((not found)\n);
+   return FDT_ADDR_T_NONE;
+   }
+
+   end = ptr + len / sizeof(*ptr);
+
+   if (ptr + na + ns  end) {
+   debug((not enough data: expected %d bytes, got %d bytes)\n,
+ (na + ns) * 4, len);
+   return FDT_ADDR_T_NONE;
+   }
+
+   addr = fdtdec_get_number(ptr, na);
+
+   if (sizep) {
+   *sizep = fdtdec_get_number(ptr + na, ns);
+   debug(addr=%pa, size=%pa\n, addr, sizep);
+   } else {
+   debug(%pa\n, addr);
+   }
+
+   return addr;
 }
 
 fdt_addr_t fdtdec_get_addr(const void *blob, int node,
-- 
1.9.1

___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot