[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