[PATCH v2] bsps/shared/ofw: Implement RTEMS OFW interface

Niteesh G. S. niteesh.gs at gmail.com
Fri Aug 21 19:04:33 UTC 2020


Hello,
On Fri, Aug 21, 2020 at 10:58 PM Niteesh G. S. <niteesh.gs at gmail.com> wrote:

>
>> diff --git a/bsps/shared/ofw/ofw.c b/bsps/shared/ofw/ofw.c
>> new file mode 100644
>> index 0000000000..481b29553b
>> --- /dev/null
>> +++ b/bsps/shared/ofw/ofw.c
>> @@ -0,0 +1,670 @@
>> +/* SPDX-License-Identifier: BSD-2-Clause */
>> +
>> +/**
>> + * @file
>> + *
>> + * @ingroup ofw
>> + */
>> +
>> +/*
>> + * Copyright (C) 2020 Niteesh Babu G S <niteesh.gs at gmail.com>
>> + *
>> + * Redistribution and use in source and binary forms, with or without
>> + * modification, are permitted provided that the following conditions
>> + * are met:
>> + * 1. Redistributions of source code must retain the above copyright
>> + *    notice, this list of conditions and the following disclaimer.
>> + * 2. Redistributions in binary form must reproduce the above copyright
>> + *    notice, this list of conditions and the following disclaimer in the
>> + *    documentation and/or other materials provided with the
>> distribution.
>> + *
>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>> "AS IS"
>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
>> THE
>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>> PURPOSE
>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
>> BE
>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>> BUSINESS
>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
>> IN
>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>> OTHERWISE)
>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>> OF THE
>> + * POSSIBILITY OF SUCH DAMAGE.
>> + */
>> +
>> +#ifdef HAVE_CONFIG_H
>> +#include "config.h"
>> +#endif
>> +
>> +#include <bsp/fdt.h>
>> +#include <sys/param.h>
>> +#include <ofw/ofw.h>
>> +#include <libfdt.h>
>> +#include <assert.h>
>> +#include <rtems/sysinit.h>
>> +
>> +const void *fdtp = NULL;
>> +
>> +static phandle_t rtems_fdt_offset_to_phandle( int offset )
>> +{
>> +  if (offset < 0) {
>> +    return 0;
>> +  }
>> +
>> +  return (phandle_t)offset + fdt_off_dt_struct(fdtp);
>> +}
>> +
>> +static int rtems_fdt_phandle_to_offset( phandle_t handle )
>> +{
>> +  int off;
>> +  int fdt_off;
>> +
>> +  off = (int) handle;
>> +  fdt_off = fdt_off_dt_struct(fdtp);
>> +
>> +  if (off < fdt_off) {
>> +    return -1;
>> +
>> +  }
>> +
>> +  return off - fdt_off;
>> +}
>> +
>> +static void rtems_ofw_init( void ) {
>> +  int rv;
>> +  const void *fdt;
>> +
>> +  fdt = bsp_fdt_get();
>> +
>> +  rv = fdt_check_header(fdt);
>> +
>> +  /*
>> +   * If the FDT is invalid exit through fatal.
>> +   */
>> +  if (rv != 0) {
>> +    rtems_fatal_error_occurred(RTEMS_NOT_CONFIGURED);
>> +  }
>> +
>> +  fdtp = fdt;
>> +}
>> +
>> +RTEMS_SYSINIT_ITEM(
>> +  rtems_ofw_init,
>> +  RTEMS_SYSINIT_BSP_PRE_DRIVERS,
>> +  RTEMS_SYSINIT_ORDER_FIRST
>> +);
>> +
>> +phandle_t rtems_ofw_peer( phandle_t node )
>> +{
>> +  int offset;
>> +
>> +  if (node == 0) {
>> +    int root = fdt_path_offset(fdtp, "/");
>> +    return rtems_fdt_offset_to_phandle(root);
>> +  }
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +  if (offset < 0) {
>> +    return 0;
>> +  }
>> +
>> +  offset = fdt_next_subnode(fdtp, offset);
>> +  return rtems_fdt_offset_to_phandle(offset);
>> +}
>> +
>> +phandle_t rtems_ofw_child( phandle_t node )
>> +{
>> +  int offset;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0) {
>> +    return 0;
>> +  }
>> +
>> +  offset = fdt_first_subnode(fdtp, offset);
>> +  return rtems_fdt_offset_to_phandle(offset);
>> +}
>> +
>> +phandle_t rtems_ofw_parent( phandle_t node )
>> +{
>> +  int offset;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0) {
>> +    return 0;
>> +  }
>> +
>> +  offset = fdt_parent_offset(fdtp, offset);
>> +  return rtems_fdt_offset_to_phandle(offset);
>> +}
>> +
>> +size_t rtems_ofw_get_prop_len(
>> +  phandle_t node,
>> +  const char *propname
>> +)
>> +{
>> +  int offset;
>> +  int len;
>> +  const void *prop;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0) {
>> +    return -1;
>> +  }
>> +
>> +  prop = fdt_getprop(fdtp, offset, propname, &len);
>> +
>> +  if (prop == NULL && strcmp(propname, "name") == 0) {
>> +    fdt_get_name(fdtp, offset, &len);
>> +    return len + 1;
>> +  }
>> +
>> +  if (prop == NULL && strcmp(propname, "/chosen") == 0) {
>> +    if (strcmp(propname, "fdtbootcpu") == 0)
>> +      return sizeof(pcell_t);
>> +    if (strcmp(propname, "fdtmemreserv") == 0)
>> +      return 2 * sizeof(uint64_t) * fdt_num_mem_rsv(fdtp);
>> +  }
>> +
>> +  if (prop == NULL) {
>> +    return -1;
>> +  }
>> +
>> +  return len;
>> +}
>> +
>> +size_t rtems_ofw_get_prop(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  void        *buf,
>> +  size_t       bufsize
>> +)
>> +{
>> +  const void *prop;
>> +  int offset;
>> +  int len;
>> +  uint32_t cpuid;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0) {
>> +    return -1;
>> +  }
>> +
>> +  prop = fdt_getprop(fdtp, offset, propname, &len);
>> +
>> +  if (prop == NULL && strcmp(propname, "name") == 0) {
>> +    prop = fdt_get_name(fdtp, offset, &len);
>> +    strncpy(buf, prop, bufsize);
>> +    return len + 1;
>> +  }
>> +
>> +  if (prop == NULL && strcmp(propname, "/chosen") == 0) {
>> +    if (strcmp(propname, "fdtbootcpu") == 0) {
>> +      cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp));
>> +      len = sizeof(cpuid);
>> +      prop = &cpuid;
>> +    }
>> +    if (strcmp(propname, "fdtmemreserv") == 0) {
>> +      prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp);
>> +      len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp);
>> +    }
>> +  }
>> +
>> +  if (prop == NULL) {
>> +    return -1;
>> +  }
>> +
>> +  bcopy(prop, buf, MIN(len, bufsize));
>> +
>> +  return len;
>> +}
>> +
>> +size_t rtems_ofw_get_enc_prop(
>> +  phandle_t    node,
>> +  const char  *prop,
>> +  pcell_t     *buf,
>> +  size_t       len
>> +)
>> +{
>> +  size_t rv;
>> +
>> +  assert(len % 4 == 0);
>> +  rv = rtems_ofw_get_prop(node, prop, buf, len);
>> +
>> +  if (rv < 0) {
>> +    return rv;
>> +  }
>> +
>> +  for (int i = 0; i < (len / 4); i++) {
>> +    buf[i] = fdt32_to_cpu(buf[i]);
>> +  }
>> +
>> +  return rv;
>> +}
>> +
>> +int rtems_ofw_has_prop(
>> +  phandle_t    node,
>> +  const char  *propname
>> +)
>> +{
>> +  size_t rv;
>> +
>> +  rv = rtems_ofw_get_prop_len(node, propname);
>> +  return rv >= 0 ? 1 : 0;
>> +}
>> +
>> +size_t rtems_ofw_search_prop(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  void        *buf,
>> +  size_t       len
>> +)
>> +{
>> +  size_t rv;
>> +
>> +  for (; node != 0; node = rtems_ofw_parent(node)) {
>> +    if ((rv = rtems_ofw_get_prop(node, propname, buf, len) != -1)) {
>> +      return rv;
>> +    }
>> +  }
>> +
>> +  return -1;
>> +}
>> +
>> +size_t rtems_ofw_search_enc_prop(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  pcell_t     *buf,
>> +  size_t       len
>> +)
>> +{
>> +  size_t rv;
>> +
>> +  for (; node != 0; node = rtems_ofw_parent(node)) {
>> +    if ((rv = rtems_ofw_get_enc_prop(node, propname, buf, len) != -1)) {
>> +      return rv;
>> +    }
>> +  }
>> +
>> +  return -1;
>> +}
>> +
>> +size_t rtems_ofw_get_prop_alloc(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  void       **buf
>> +)
>> +{
>> +  size_t len;
>> +
>> +  *buf = NULL;
>> +  if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) {
>> +    return -1;
>> +  }
>> +
>> +  if (len > 0) {
>> +    *buf = malloc(len);
>> +
>> +    if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) {
>> +      rtems_ofw_free(buf);
>> +      *buf = NULL;
>> +      return -1;
>> +    }
>> +  }
>> +
>> +  return len;
>> +}
>> +
>> +size_t rtems_ofw_get_prop_alloc_multi(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  int          elsz,
>> +  void       **buf
>> +)
>> +{
>> +  size_t len;
>> +
>> +  *buf = NULL;
>> +  if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 ||
>> +      (len % elsz != 0)) {
>> +    return -1;
>> +  }
>>
>
> While going through the code again, a question raised inside me,
> In the above code, the function rtems_ofw_get_prop_len returns
> a size_t which is an unsigned value, I compare that to -1 is that
> OK from a code review point of view or should I change the type
> of len to -1?
>

UPDATE: I should have been using ssize_t, I always thought ssize_t and
size_t were both the same type. But after googling I realized that ssize_t
is signed, unlike size_t which is unsigned.

I have updated the local commit to use ssize_t instead of size_t as return
type and as variable types in some places. So please ignore this issue
during code review. Sorry for the mistake.

> +
>> +  if (len > 0) {
>> +    *buf = malloc(len);
>> +
>> +    if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) {
>> +      rtems_ofw_free(buf);
>> +      *buf = NULL;
>> +      return -1;
>> +    }
>> +  }
>> +
>> +  return (len / elsz);
>> +}
>> +
>> +size_t rtems_ofw_get_enc_prop_alloc(
>> +  phandle_t    node,
>> +  const char  *propname,
>> +  void       **buf
>> +)
>> +{
>> +  size_t len;
>> +
>> +  *buf = NULL;
>> +  if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) {
>> +    return -1;
>> +  }
>> +
>> +  if (len > 0) {
>> +    *buf = malloc(len);
>> +
>> +    if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) {
>> +      rtems_ofw_free(buf);
>> +      *buf = NULL;
>> +      return -1;
>> +    }
>> +  }
>> +
>> +  return len;
>> +}
>> +
>> +size_t rtems_ofw_get_enc_prop_alloc_multi(
>> +  phandle_t     node,
>> +  const char   *propname,
>> +  int           elsz,
>> +  void        **buf
>> +)
>> +{
>> +  size_t len;
>> +
>> +  *buf = NULL;
>> +  if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 ||
>> +      (len % elsz != 0)) {
>> +    return -1;
>> +  }
>> +
>> +  if (len > 0) {
>> +    *buf = malloc(len);
>> +
>> +    if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) {
>> +      rtems_ofw_free(buf);
>> +      *buf = NULL;
>> +      return -1;
>> +    }
>> +  }
>> +
>> +  return (len / elsz);
>> +}
>> +
>> +void rtems_ofw_free( void *buf )
>> +{
>> +  free(buf);
>> +}
>> +
>> +int rtems_ofw_next_prop(
>> +  phandle_t    node,
>> +  const char  *previous,
>> +  char        *buf,
>> +  size_t       len
>> +)
>> +{
>> +  const void *name;
>> +  const void *prop;
>> +  int offset;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0) {
>> +    return -1;
>> +  }
>> +
>> +  if (previous == NULL) {
>> +    offset = fdt_first_property_offset(fdtp, offset);
>> +  } else {
>> +    fdt_for_each_property_offset(offset, fdtp, offset) {
>> +      prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name,
>> NULL);
>> +      if (prop == NULL)
>> +        return -1;
>> +
>> +      if (strcmp(previous, name) != 0)
>> +        continue;
>> +
>> +      offset = fdt_next_property_offset(fdtp, offset);
>> +      break;
>> +    }
>> +  }
>> +
>> +  if (offset < 0)
>> +    return 0;
>> +
>> +  prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name,
>> &offset);
>> +  if (prop == NULL)
>> +    return -1;
>> +
>> +  strncpy(buf, name, len);
>> +
>> +  return 1;
>> +}
>> +
>> +int rtems_ofw_set_prop(
>> +  phandle_t    node,
>> +  const char  *name,
>> +  const void  *buf,
>> +  size_t       len
>> +)
>> +{
>> +  int offset;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  if (offset < 0)
>> +    return -1;
>> +
>> +  if (fdt_setprop_inplace(fdtp, offset, name, buf, len) != 0)
>> +    return (fdt_setprop(fdtp, offset, name, buf, len));
>> +
>> +  return 0;
>> +}
>> +
>> +phandle_t rtems_ofw_find_device( const char *path )
>> +{
>> +  int offset;
>> +
>> +  offset = fdt_path_offset(fdtp, path);
>> +  if (offset < 0)
>> +    return -1;
>> +
>> +  return rtems_fdt_offset_to_phandle(offset);
>> +}
>> +
>> +static phandle_t rtems_ofw_get_effective_phandle(
>> +  phandle_t node,
>> +  phandle_t xref
>> +)
>> +{
>> +  phandle_t child;
>> +  phandle_t ref;
>> +
>> +  for (child = rtems_ofw_child(node); child != 0; child =
>> rtems_ofw_peer(child)) {
>> +    ref = rtems_ofw_get_effective_phandle(child, xref);
>> +    if (ref != -1)
>> +      return ref;
>> +
>> +    if (rtems_ofw_get_enc_prop(child, "phandle", &ref, sizeof(ref)) ==
>> -1 &&
>> +        rtems_ofw_get_enc_prop(child, "ibm,phandle", &ref, sizeof(ref))
>> == -1 &&
>> +        rtems_ofw_get_enc_prop(child, "linux,phandle", &ref,
>> sizeof(ref)) == -1
>> +    ) {
>> +      continue;
>> +    }
>> +
>> +    if (ref == xref)
>> +      return child;
>> +  }
>> +
>> +  return -1;
>> +}
>> +
>> +phandle_t rtems_ofw_node_from_xref( phandle_t xref )
>> +{
>> +  phandle_t node;
>> +
>> +  if ((node = rtems_ofw_get_effective_phandle(rtems_ofw_peer(0), xref))
>> == -1)
>> +    return xref;
>> +
>> +  return node;
>> +}
>> +
>> +phandle_t rtems_ofw_xref_from_node( phandle_t node )
>> +{
>> +  phandle_t ref;
>> +
>> +    if (rtems_ofw_get_enc_prop(node, "phandle", &ref, sizeof(ref)) == -1
>> &&
>> +        rtems_ofw_get_enc_prop(node, "ibm,phandle", &ref, sizeof(ref))
>> == -1 &&
>> +        rtems_ofw_get_enc_prop(node, "linux,phandle", &ref, sizeof(ref))
>> == -1)
>> +    {
>> +      return node;
>> +    }
>> +
>> +    return ref;
>> +}
>> +
>> +phandle_t rtems_ofw_instance_to_package( ihandle_t instance )
>> +{
>> +  return rtems_ofw_node_from_xref(instance);
>> +}
>> +
>> +size_t rtems_ofw_package_to_path(
>> +  phandle_t   node,
>> +  char       *buf,
>> +  size_t      len
>> +)
>> +{
>> +  int offset;
>> +  int rv;
>> +
>> +  offset = rtems_fdt_phandle_to_offset(node);
>> +
>> +  rv = fdt_get_path(fdtp, offset, buf, len);
>> +  if (rv != 0)
>> +    return -1;
>> +
>> +  return rv;
>> +}
>> +
>> +size_t rtems_ofw_instance_to_path(
>> +  ihandle_t  instance,
>> +  char      *buf,
>> +  size_t     len
>> +)
>> +{
>> +  int offset;
>> +  int rv;
>> +
>> +  offset = rtems_ofw_instance_to_package(instance);
>> +  offset = rtems_fdt_phandle_to_offset(offset);
>> +
>> +  rv = fdt_get_path(fdtp, offset, buf, len);
>> +  if (rv != 0)
>> +    return -1;
>> +
>> +  return rv;
>> +}
>> +
>> +int rtems_ofw_get_reg(
>> +  phandle_t              node,
>> +  rtems_ofw_memory_area *buf,
>> +  size_t                 size
>> +)
>> +{
>> +  int len;
>> +  int offset;
>> +  int nranges;
>> +  int nregs;
>> +  phandle_t parent;
>> +  rtems_ofw_ranges range;
>> +  const rtems_ofw_ranges *ptr;
>> +
>> +  len = rtems_ofw_get_enc_prop(node, "reg", (pcell_t *)buf, size);
>> +  if (len <= 0) {
>> +    return len;
>> +  }
>> +
>> +  nregs = MIN(len, size) / sizeof(rtems_ofw_memory_area);
>> +
>> +  for (parent = rtems_ofw_parent(node); parent > 0;
>> +      parent = rtems_ofw_parent(parent)) {
>> +
>> +    offset = rtems_fdt_phandle_to_offset(parent);
>> +    ptr = fdt_getprop(fdtp, offset, "ranges", &len);
>> +
>> +    if (len < 0) {
>> +      break;
>> +    }
>> +
>> +    nranges = len / sizeof(rtems_ofw_ranges);
>> +
>> +    offset = 0;
>> +    for (int i=0; i < nregs; i++) {
>> +      for (int j=0; j < nranges; j++) {
>> +
>> +        range.parent_bus = fdt32_to_cpu(ptr[j].parent_bus);
>> +        range.child_bus = fdt32_to_cpu(ptr[j].child_bus);
>> +        range.size = fdt32_to_cpu(ptr[j].size);
>> +
>> +        if (buf[i].start >= range.child_bus &&
>> +            buf[i].start < range.child_bus + range.size) {
>> +          offset = range.parent_bus - range.child_bus;
>> +          break;
>> +        }
>> +
>> +      }
>> +      buf[i].start += offset;
>> +    }
>> +  }
>> +
>> +  return nregs;
>> +}
>> +
>> +int rtems_ofw_get_interrupts(
>> +  phandle_t            node,
>> +  rtems_vector_number *buf,
>> +  size_t               size
>> +)
>> +{
>> +  int rv;
>> +
>> +  rv = rtems_ofw_get_enc_prop(node, "interrupts", buf, size);
>> +
>> +  if (rv <= 0) {
>> +    return rv;
>> +  }
>> +
>> +  return MIN(size, rv) / sizeof(rtems_vector_number);
>> +}
>> +
>> +bool rtems_ofw_node_status( phandle_t node )
>> +{
>> +  int len;
>> +  const char buf[10];
>> +
>> +  len = rtems_ofw_get_prop(node, "status", &buf[0], sizeof(buf));
>> +  if ((len == -1) ||
>> +      (strncmp(buf, "okay", MIN(5, len)) == 0) ||
>> +      (strncmp(buf, "ok", MIN(3, len)) == 0)) {
>> +      return true;
>> +  }
>> +
>> +  return false;
>> +}
>> +
>> +phandle_t rtems_ofw_find_device_by_compat( const char *compat )
>> +{
>> +  int offset;
>> +
>> +  offset = fdt_node_offset_by_compatible(fdtp, -1, compat);
>> +  return rtems_fdt_offset_to_phandle(offset);
>> +}
>> diff --git a/spec/build/bsps/obj.yml b/spec/build/bsps/obj.yml
>> index 8809238057..141ba25f5e 100644
>> --- a/spec/build/bsps/obj.yml
>> +++ b/spec/build/bsps/obj.yml
>> @@ -24,6 +24,9 @@ install:
>>    - bsps/include/bsp/u-boot.h
>>    - bsps/include/bsp/uart-output-char.h
>>    - bsps/include/bsp/utility.h
>> +- destination: ${BSP_INCLUDEDIR}/ofw
>> +  source:
>> +  - bsps/include/ofw/ofw.h
>>  - destination: ${BSP_INCLUDEDIR}/libchip
>>    source:
>>    - bsps/include/libchip/am29lv160.h
>> @@ -104,4 +107,5 @@ source:
>>  - bsps/shared/dev/serial/z85c30_reg.c
>>  - bsps/shared/start/bootcard.c
>>  - bsps/shared/rtems-version.c
>> +- bsps/shared/ofw/ofw.c
>>  type: build
>> --
>> 2.17.1
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20200822/e5670fc4/attachment-0001.html>


More information about the devel mailing list