root/sys/dev/bhnd/nvram/bhnd_nvram_storevar.h
/*-
 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
 * All rights reserved.
 *
 * 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,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
 *    redistribution must be conditioned upon including a substantially
 *    similar Disclaimer requirement for further binary redistribution.
 *
 * NO WARRANTY
 * 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 NONINFRINGEMENT, MERCHANTIBILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
 * 
 */

#ifndef _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_
#define _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_

#include <sys/types.h>

#ifndef _KERNEL
#include <pthread.h>
#endif

#include "bhnd_nvram_plist.h"

#include "bhnd_nvram_store.h"

/** Index is only generated if minimum variable count is met */
#define BHND_NV_IDX_VAR_THRESHOLD       15

#define BHND_NVSTORE_ROOT_PATH          "/"
#define BHND_NVSTORE_ROOT_PATH_LEN      sizeof(BHND_NVSTORE_ROOT_PATH)

#define BHND_NVSTORE_GET_FLAG(_value, _flag)    \
        (((_value) & BHND_NVSTORE_ ## _flag) != 0)
#define BHND_NVSTORE_GET_BITS(_value, _field)   \
        ((_value) & BHND_NVSTORE_ ## _field ## _MASK)

/* Forward declarations */
typedef struct bhnd_nvstore_name_info   bhnd_nvstore_name_info;
typedef struct bhnd_nvstore_index       bhnd_nvstore_index;
typedef struct bhnd_nvstore_path        bhnd_nvstore_path;

typedef struct bhnd_nvstore_alias       bhnd_nvstore_alias;

typedef struct bhnd_nvstore_alias_list  bhnd_nvstore_alias_list;
typedef struct bhnd_nvstore_update_list bhnd_nvstore_update_list;
typedef struct bhnd_nvstore_path_list   bhnd_nvstore_path_list;

LIST_HEAD(bhnd_nvstore_alias_list,      bhnd_nvstore_alias);
LIST_HEAD(bhnd_nvstore_update_list,     bhnd_nvstore_update);
LIST_HEAD(bhnd_nvstore_path_list,       bhnd_nvstore_path);

/**
 * NVRAM store variable entry types.
 */
typedef enum {
        BHND_NVSTORE_VAR        = 0,    /**< simple variable (var=...) */
        BHND_NVSTORE_ALIAS_DECL = 1,    /**< alias declaration ('devpath0=pci/1/1') */  
} bhnd_nvstore_var_type;

/**
 * NVRAM path descriptor types.
 */
typedef enum {
        BHND_NVSTORE_PATH_STRING        = 0,    /**< path is a string value */
        BHND_NVSTORE_PATH_ALIAS         = 1     /**< path is an alias reference */
} bhnd_nvstore_path_type;

/**
 * NVRAM variable namespaces.
 */
typedef enum {
        BHND_NVSTORE_NAME_INTERNAL      = 1,    /**< internal namespace. permits
                                                     use of reserved devpath and
                                                     alias name prefixes. */
        BHND_NVSTORE_NAME_EXTERNAL      = 2,    /**< external namespace. forbids
                                                     use of name prefixes used
                                                     for device path handling */
} bhnd_nvstore_name_type;

bhnd_nvstore_path       *bhnd_nvstore_path_new(const char *path_str,
                             size_t path_len);
void                     bhnd_nvstore_path_free(struct bhnd_nvstore_path *path);

bhnd_nvstore_index      *bhnd_nvstore_index_new(size_t capacity);
void                     bhnd_nvstore_index_free(bhnd_nvstore_index *index);
int                      bhnd_nvstore_index_append(struct bhnd_nvram_store *sc,
                             bhnd_nvstore_index *index,
                             void *cookiep);
int                      bhnd_nvstore_index_prepare(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_index *index);
void                    *bhnd_nvstore_index_lookup(struct bhnd_nvram_store *sc,
                             bhnd_nvstore_index *index, const char *name);

bhnd_nvstore_path       *bhnd_nvstore_get_root_path(
                            struct bhnd_nvram_store *sc);
bool                     bhnd_nvstore_is_root_path(struct bhnd_nvram_store *sc,
                             bhnd_nvstore_path *path);

void                    *bhnd_nvstore_path_data_next(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_path *path, void **indexp);
void                    *bhnd_nvstore_path_data_lookup(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_path *path, const char *name);
bhnd_nvram_prop         *bhnd_nvstore_path_get_update(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_path *path, const char *name);
int                      bhnd_nvstore_path_register_update(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_path *path, const char *name,
                             bhnd_nvram_val *value);

bhnd_nvstore_alias      *bhnd_nvstore_find_alias(struct bhnd_nvram_store *sc,
                             const char *path);
bhnd_nvstore_alias      *bhnd_nvstore_get_alias(struct bhnd_nvram_store *sc,
                             u_long alias_val);

bhnd_nvstore_path       *bhnd_nvstore_get_path(struct bhnd_nvram_store *sc,
                             const char *path, size_t path_len);
bhnd_nvstore_path       *bhnd_nvstore_resolve_path_alias(
                             struct bhnd_nvram_store *sc, u_long aval);

bhnd_nvstore_path       *bhnd_nvstore_var_get_path(struct bhnd_nvram_store *sc,
                             bhnd_nvstore_name_info *info);
int                      bhnd_nvstore_var_register_path(
                             struct bhnd_nvram_store *sc,
                             bhnd_nvstore_name_info *info, void *cookiep);

int                      bhnd_nvstore_register_path(struct bhnd_nvram_store *sc,
                             const char *path, size_t path_len);
int                      bhnd_nvstore_register_alias(
                             struct bhnd_nvram_store *sc,
                             const bhnd_nvstore_name_info *info, void *cookiep);

const char              *bhnd_nvstore_parse_relpath(const char *parent,
                             const char *child);
int                      bhnd_nvstore_parse_name_info(const char *name,
                             bhnd_nvstore_name_type name_type,
                             uint32_t data_caps, bhnd_nvstore_name_info *info);

/**
 * NVRAM variable name descriptor.
 * 
 * For NVRAM data instances supporting BHND_NVRAM_DATA_CAP_DEVPATHS, the
 * NVRAM-vended variable name will be in one of four formats:
 * 
 * - Simple Variable:
 *      'variable'
 * - Device Variable:
 *      'pci/1/1/variable'
 * - Device Alias Variable:
 *      '0:variable'
 * - Device Path Alias Definition:
 *      'devpath0=pci/1/1/variable'
 *
 * Device Paths:
 * 
 * The device path format is device class-specific; the known supported device
 * classes are:
 *      - sb:           BCMA/SIBA SoC core device path.
 *      - pci:          PCI device path (and PCIe on some earlier devices).
 *      - pcie:         PCIe device path.
 *      - usb:          USB device path.
 *
 * The device path format is loosely defined as '[class]/[domain]/[bus]/[slot]',
 * with missing values either assumed to be zero, a value specific to the
 * device class, or irrelevant to the device class in question.
 * 
 * Examples:
 *      sb/1                    BCMA/SIBA backplane 0, core 1.
 *      pc/1/1                  PCMCIA bus 1, slot 1
 *      pci/1/1                 PCI/PCIe domain 0, bus 1, device 1
 *      pcie/1/1                PCIe domain 0, bus 1, device 1
 *      usb/0xbd17              USB PID 0xbd17 (VID defaults to Broadcom 0x0a5c)
 *
 * Device Path Aliases:
 * 
 * Device path aliases reduce duplication of device paths in the flash encoding
 * of NVRAM data; a single devpath[alias]=[devpath] variable entry is defined,
 * and then later variables may reference the device path via its alias:
 *      devpath1=usb/0xbd17
 *      1:mcs5gpo0=0x1100
 * 
 * Alias values are always positive, base 10 integers.
 */
struct bhnd_nvstore_name_info {
        const char              *name;          /**< variable name */
        bhnd_nvstore_var_type    type;          /**< variable type */
        bhnd_nvstore_path_type   path_type;     /**< path type */

        /** Path information */
        union {
                /* BHND_NVSTORE_PATH_STRING */
                struct {
                        const char      *value;         /**< device path */
                        size_t           value_len;     /**< device path length */
                } str;

                /** BHND_NVSTORE_PATH_ALIAS */
                struct {
                        u_long           value;         /**< device alias */
                } alias;
        } path;
};

/**
 * NVRAM variable index.
 * 
 * Provides effecient name-based lookup by maintaining an array of cached
 * cookiep values, sorted lexicographically by relative variable name.
 */
struct bhnd_nvstore_index {
        size_t   count;         /**< entry count */
        size_t   capacity;      /**< entry capacity */
        void    *cookiep[];     /**< cookiep values */
};

/**
 * NVRAM device path.
 */
struct bhnd_nvstore_path {
        char                            *path_str;      /**< canonical path string */
        size_t                           num_vars;      /**< per-path count of committed
                                                             (non-pending) variables */
        bhnd_nvstore_index              *index;         /**< per-path index, or NULL if
                                                             this is a root path for
                                                             which the data source
                                                             may be queried directly. */
        bhnd_nvram_plist                *pending;       /**< pending changes */

        LIST_ENTRY(bhnd_nvstore_path) np_link;
};

/**
 * NVRAM device path alias.
 */
struct bhnd_nvstore_alias {
        bhnd_nvstore_path       *path;          /**< borrowed path reference */
        void                    *cookiep;       /**< NVRAM variable's cookiep value */
        u_long                   alias;         /**< alias value */

        LIST_ENTRY(bhnd_nvstore_alias) na_link;
};

/** bhnd nvram store instance state */
struct bhnd_nvram_store {
#ifdef _KERNEL
        struct mtx               mtx;
#else
        pthread_mutex_t          mtx;
#endif
        struct bhnd_nvram_data  *data;          /**< backing data */
        uint32_t                 data_caps;     /**< data capability flags */
        bhnd_nvram_plist        *data_opts;     /**< data serialization options */

        bhnd_nvstore_alias_list  aliases[4];    /**< path alias hash table */
        size_t                   num_aliases;   /**< alias count */

        bhnd_nvstore_path       *root_path;     /**< root path instance */
        bhnd_nvstore_path_list   paths[4];      /**< path hash table */
        size_t                   num_paths;     /**< path count */
};

#ifdef _KERNEL

#define BHND_NVSTORE_LOCK_INIT(sc) \
        mtx_init(&(sc)->mtx, "BHND NVRAM store lock", NULL, MTX_DEF)
#define BHND_NVSTORE_LOCK(sc)                   mtx_lock(&(sc)->mtx)
#define BHND_NVSTORE_UNLOCK(sc)                 mtx_unlock(&(sc)->mtx)
#define BHND_NVSTORE_LOCK_ASSERT(sc, what)      mtx_assert(&(sc)->mtx, what)
#define BHND_NVSTORE_LOCK_DESTROY(sc)           mtx_destroy(&(sc)->mtx)

#else /* !_KERNEL */

#define BHND_NVSTORE_LOCK_INIT(sc)      do {                            \
        int error = pthread_mutex_init(&(sc)->mtx, NULL);               \
        if (error)                                                      \
                BHND_NV_PANIC("pthread_mutex_init() failed: %d",        \
                    error);                                             \
} while(0)

#define BHND_NVSTORE_LOCK(sc)           pthread_mutex_lock(&(sc)->mtx)
#define BHND_NVSTORE_UNLOCK(sc)         pthread_mutex_unlock(&(sc)->mtx)
#define BHND_NVSTORE_LOCK_DESTROY(sc)   pthread_mutex_destroy(&(sc)->mtx)
#define BHND_NVSTORE_LOCK_ASSERT(sc, what)

#endif /* _KERNEL */

#endif /* _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_ */