root/sys/dev/dpaa2/dpaa2_mcp.h
/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright © 2021-2022 Dmitry Salychev
 *
 * 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 AUTHOR 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 AUTHOR 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.
 */

#ifndef _DPAA2_MCP_H
#define _DPAA2_MCP_H

#include <sys/rman.h>
#include <sys/mutex.h>

#include "dpaa2_types.h"

/*
 * DPAA2 MC command interface helper routines.
 */

#define DPAA2_PORTAL_TIMEOUT            100000  /* us */
#define DPAA2_MCP_MEM_WIDTH             0x40 /* Minimal size of the MC portal. */
#define DPAA2_MCP_MAX_RESOURCES         1 /* resources per DPMCP: 1 SYS_MEM */

/*
 * Portal flags.
 *
 * TODO: Use the same flags for both MC and software portals.
 */
#define DPAA2_PORTAL_DEF                0x0u
#define DPAA2_PORTAL_NOWAIT_ALLOC       0x2u    /* Do not sleep during init */
#define DPAA2_PORTAL_LOCKED             0x4000u /* Wait till portal's unlocked */
#define DPAA2_PORTAL_DESTROYED          0x8000u /* Terminate any operations */

/* Command flags. */
#define DPAA2_CMD_DEF                   0x0u
#define DPAA2_CMD_HIGH_PRIO             0x80u   /* High priority command */
#define DPAA2_CMD_INTR_DIS              0x100u  /* Disable cmd finished intr */
#define DPAA2_CMD_NOWAIT_ALLOC          0x8000u /* Do not sleep during init */

/* DPAA2 command return codes. */
#define DPAA2_CMD_STAT_OK               0x0     /* Set by MC on success */
#define DPAA2_CMD_STAT_READY            0x1     /* Ready to be processed */
#define DPAA2_CMD_STAT_AUTH_ERR         0x3     /* Illegal object-portal-icid */
#define DPAA2_CMD_STAT_NO_PRIVILEGE     0x4     /* No privilege */
#define DPAA2_CMD_STAT_DMA_ERR          0x5     /* DMA or I/O error */
#define DPAA2_CMD_STAT_CONFIG_ERR       0x6     /* Invalid/conflicting params */
#define DPAA2_CMD_STAT_TIMEOUT          0x7     /* Command timed out */
#define DPAA2_CMD_STAT_NO_RESOURCE      0x8     /* No DPAA2 resources */
#define DPAA2_CMD_STAT_NO_MEMORY        0x9     /* No memory available */
#define DPAA2_CMD_STAT_BUSY             0xA     /* Device is busy */
#define DPAA2_CMD_STAT_UNSUPPORTED_OP   0xB     /* Unsupported operation */
#define DPAA2_CMD_STAT_INVALID_STATE    0xC     /* Invalid state */
/* Driver-specific return codes. */
#define DPAA2_CMD_STAT_UNKNOWN_OBJ      0xFD    /* Unknown DPAA2 object. */
#define DPAA2_CMD_STAT_EINVAL           0xFE    /* Invalid argument */
#define DPAA2_CMD_STAT_ERR              0xFF    /* General error */

/* Object's memory region flags. */
#define DPAA2_RC_REG_CACHEABLE          0x1     /* Cacheable memory mapping */

#define DPAA2_HW_FLAG_HIGH_PRIO         0x80u
#define DPAA2_SW_FLAG_INTR_DIS          0x01u

#define DPAA2_CMD_PARAMS_N              7u
#define DPAA2_LABEL_SZ                  16

/* ------------------------- MNG command IDs -------------------------------- */
#define CMD_MNG_BASE_VERSION    1
#define CMD_MNG_ID_OFFSET       4

#define CMD_MNG(id)     (((id) << CMD_MNG_ID_OFFSET) | CMD_MNG_BASE_VERSION)

#define CMDID_MNG_GET_VER                       CMD_MNG(0x831)
#define CMDID_MNG_GET_SOC_VER                   CMD_MNG(0x832)
#define CMDID_MNG_GET_CONT_ID                   CMD_MNG(0x830)

/* ------------------------- DPRC command IDs ------------------------------- */
#define CMD_RC_BASE_VERSION     1
#define CMD_RC_2ND_VERSION      2
#define CMD_RC_3RD_VERSION      3
#define CMD_RC_ID_OFFSET        4

#define CMD_RC(id)      (((id) << CMD_RC_ID_OFFSET) | CMD_RC_BASE_VERSION)
#define CMD_RC_V2(id)   (((id) << CMD_RC_ID_OFFSET) | CMD_RC_2ND_VERSION)
#define CMD_RC_V3(id)   (((id) << CMD_RC_ID_OFFSET) | CMD_RC_3RD_VERSION)

#define CMDID_RC_OPEN                           CMD_RC(0x805)
#define CMDID_RC_CLOSE                          CMD_RC(0x800)
#define CMDID_RC_GET_API_VERSION                CMD_RC(0xA05)
#define CMDID_RC_GET_ATTR                       CMD_RC(0x004)
#define CMDID_RC_RESET_CONT                     CMD_RC(0x005)
#define CMDID_RC_RESET_CONT_V2                  CMD_RC_V2(0x005)
#define CMDID_RC_SET_IRQ                        CMD_RC(0x010)
#define CMDID_RC_SET_IRQ_ENABLE                 CMD_RC(0x012)
#define CMDID_RC_SET_IRQ_MASK                   CMD_RC(0x014)
#define CMDID_RC_GET_IRQ_STATUS                 CMD_RC(0x016)
#define CMDID_RC_CLEAR_IRQ_STATUS               CMD_RC(0x017)
#define CMDID_RC_GET_CONT_ID                    CMD_RC(0x830)
#define CMDID_RC_GET_OBJ_COUNT                  CMD_RC(0x159)
#define CMDID_RC_GET_OBJ                        CMD_RC(0x15A)
#define CMDID_RC_GET_OBJ_DESC                   CMD_RC(0x162)
#define CMDID_RC_GET_OBJ_REG                    CMD_RC(0x15E)
#define CMDID_RC_GET_OBJ_REG_V2                 CMD_RC_V2(0x15E)
#define CMDID_RC_GET_OBJ_REG_V3                 CMD_RC_V3(0x15E)
#define CMDID_RC_SET_OBJ_IRQ                    CMD_RC(0x15F)
#define CMDID_RC_GET_CONN                       CMD_RC(0x16C)

/* ------------------------- DPIO command IDs ------------------------------- */
#define CMD_IO_BASE_VERSION     1
#define CMD_IO_ID_OFFSET        4

#define CMD_IO(id)      (((id) << CMD_IO_ID_OFFSET) | CMD_IO_BASE_VERSION)

#define CMDID_IO_OPEN                           CMD_IO(0x803)
#define CMDID_IO_CLOSE                          CMD_IO(0x800)
#define CMDID_IO_ENABLE                         CMD_IO(0x002)
#define CMDID_IO_DISABLE                        CMD_IO(0x003)
#define CMDID_IO_GET_ATTR                       CMD_IO(0x004)
#define CMDID_IO_RESET                          CMD_IO(0x005)
#define CMDID_IO_SET_IRQ_ENABLE                 CMD_IO(0x012)
#define CMDID_IO_SET_IRQ_MASK                   CMD_IO(0x014)
#define CMDID_IO_GET_IRQ_STATUS                 CMD_IO(0x016)
#define CMDID_IO_ADD_STATIC_DQ_CHAN             CMD_IO(0x122)

/* ------------------------- DPNI command IDs ------------------------------- */
#define CMD_NI_BASE_VERSION     1
#define CMD_NI_2ND_VERSION      2
#define CMD_NI_4TH_VERSION      4
#define CMD_NI_ID_OFFSET        4

#define CMD_NI(id)      (((id) << CMD_NI_ID_OFFSET) | CMD_NI_BASE_VERSION)
#define CMD_NI_V2(id)   (((id) << CMD_NI_ID_OFFSET) | CMD_NI_2ND_VERSION)
#define CMD_NI_V4(id)   (((id) << CMD_NI_ID_OFFSET) | CMD_NI_4TH_VERSION)

#define CMDID_NI_OPEN                           CMD_NI(0x801)
#define CMDID_NI_CLOSE                          CMD_NI(0x800)
#define CMDID_NI_ENABLE                         CMD_NI(0x002)
#define CMDID_NI_DISABLE                        CMD_NI(0x003)
#define CMDID_NI_GET_API_VER                    CMD_NI(0xA01)
#define CMDID_NI_RESET                          CMD_NI(0x005)
#define CMDID_NI_GET_ATTR                       CMD_NI(0x004)
#define CMDID_NI_SET_BUF_LAYOUT                 CMD_NI(0x265)
#define CMDID_NI_GET_TX_DATA_OFF                CMD_NI(0x212)
#define CMDID_NI_GET_PORT_MAC_ADDR              CMD_NI(0x263)
#define CMDID_NI_SET_PRIM_MAC_ADDR              CMD_NI(0x224)
#define CMDID_NI_GET_PRIM_MAC_ADDR              CMD_NI(0x225)
#define CMDID_NI_SET_LINK_CFG                   CMD_NI(0x21A)
#define CMDID_NI_GET_LINK_CFG                   CMD_NI(0x278)
#define CMDID_NI_GET_LINK_STATE                 CMD_NI(0x215)
#define CMDID_NI_SET_QOS_TABLE                  CMD_NI(0x240)
#define CMDID_NI_CLEAR_QOS_TABLE                CMD_NI(0x243)
#define CMDID_NI_SET_POOLS                      CMD_NI(0x200)
#define CMDID_NI_SET_ERR_BEHAVIOR               CMD_NI(0x20B)
#define CMDID_NI_GET_QUEUE                      CMD_NI(0x25F)
#define CMDID_NI_SET_QUEUE                      CMD_NI(0x260)
#define CMDID_NI_GET_QDID                       CMD_NI(0x210)
#define CMDID_NI_ADD_MAC_ADDR                   CMD_NI(0x226)
#define CMDID_NI_REMOVE_MAC_ADDR                CMD_NI(0x227)
#define CMDID_NI_CLEAR_MAC_FILTERS              CMD_NI(0x228)
#define CMDID_NI_SET_MFL                        CMD_NI(0x216)
#define CMDID_NI_SET_OFFLOAD                    CMD_NI(0x26C)
#define CMDID_NI_SET_IRQ_MASK                   CMD_NI(0x014)
#define CMDID_NI_SET_IRQ_ENABLE                 CMD_NI(0x012)
#define CMDID_NI_GET_IRQ_STATUS                 CMD_NI(0x016)
#define CMDID_NI_SET_UNI_PROMISC                CMD_NI(0x222)
#define CMDID_NI_SET_MULTI_PROMISC              CMD_NI(0x220)
#define CMDID_NI_GET_STATISTICS                 CMD_NI(0x25D)
#define CMDID_NI_SET_RX_TC_DIST                 CMD_NI(0x235)

/* ------------------------- DPBP command IDs ------------------------------- */
#define CMD_BP_BASE_VERSION     1
#define CMD_BP_ID_OFFSET        4

#define CMD_BP(id)      (((id) << CMD_BP_ID_OFFSET) | CMD_BP_BASE_VERSION)

#define CMDID_BP_OPEN                           CMD_BP(0x804)
#define CMDID_BP_CLOSE                          CMD_BP(0x800)
#define CMDID_BP_ENABLE                         CMD_BP(0x002)
#define CMDID_BP_DISABLE                        CMD_BP(0x003)
#define CMDID_BP_GET_ATTR                       CMD_BP(0x004)
#define CMDID_BP_RESET                          CMD_BP(0x005)

/* ------------------------- DPMAC command IDs ------------------------------ */
#define CMD_MAC_BASE_VERSION    1
#define CMD_MAC_2ND_VERSION     2
#define CMD_MAC_ID_OFFSET       4

#define CMD_MAC(id)     (((id) << CMD_MAC_ID_OFFSET) | CMD_MAC_BASE_VERSION)
#define CMD_MAC_V2(id)  (((id) << CMD_MAC_ID_OFFSET) | CMD_MAC_2ND_VERSION)

#define CMDID_MAC_OPEN                          CMD_MAC(0x80C)
#define CMDID_MAC_CLOSE                         CMD_MAC(0x800)
#define CMDID_MAC_RESET                         CMD_MAC(0x005)
#define CMDID_MAC_MDIO_READ                     CMD_MAC(0x0C0)
#define CMDID_MAC_MDIO_WRITE                    CMD_MAC(0x0C1)
#define CMDID_MAC_GET_ADDR                      CMD_MAC(0x0C5)
#define CMDID_MAC_GET_ATTR                      CMD_MAC(0x004)
#define CMDID_MAC_SET_LINK_STATE                CMD_MAC_V2(0x0C3)
#define CMDID_MAC_SET_IRQ_MASK                  CMD_MAC(0x014)
#define CMDID_MAC_SET_IRQ_ENABLE                CMD_MAC(0x012)
#define CMDID_MAC_GET_IRQ_STATUS                CMD_MAC(0x016)

/* ------------------------- DPCON command IDs ------------------------------ */
#define CMD_CON_BASE_VERSION    1
#define CMD_CON_ID_OFFSET       4

#define CMD_CON(id)     (((id) << CMD_CON_ID_OFFSET) | CMD_CON_BASE_VERSION)

#define CMDID_CON_OPEN                          CMD_CON(0x808)
#define CMDID_CON_CLOSE                         CMD_CON(0x800)
#define CMDID_CON_ENABLE                        CMD_CON(0x002)
#define CMDID_CON_DISABLE                       CMD_CON(0x003)
#define CMDID_CON_GET_ATTR                      CMD_CON(0x004)
#define CMDID_CON_RESET                         CMD_CON(0x005)
#define CMDID_CON_SET_NOTIF                     CMD_CON(0x100)

/* ------------------------- DPMCP command IDs ------------------------------ */
#define CMD_MCP_BASE_VERSION    1
#define CMD_MCP_2ND_VERSION     2
#define CMD_MCP_ID_OFFSET       4

#define CMD_MCP(id)     (((id) << CMD_MCP_ID_OFFSET) | CMD_MCP_BASE_VERSION)
#define CMD_MCP_V2(id)  (((id) << CMD_MCP_ID_OFFSET) | CMD_MCP_2ND_VERSION)

#define CMDID_MCP_CREATE                        CMD_MCP_V2(0x90B)
#define CMDID_MCP_DESTROY                       CMD_MCP(0x98B)
#define CMDID_MCP_OPEN                          CMD_MCP(0x80B)
#define CMDID_MCP_CLOSE                         CMD_MCP(0x800)
#define CMDID_MCP_RESET                         CMD_MCP(0x005)

#define DPAA2_MCP_LOCK(__mcp, __flags) do {             \
        mtx_assert(&(__mcp)->lock, MA_NOTOWNED);        \
        mtx_lock(&(__mcp)->lock);                       \
        *(__flags) = (__mcp)->flags;                    \
        (__mcp)->flags |= DPAA2_PORTAL_LOCKED;          \
} while (0)

#define DPAA2_MCP_UNLOCK(__mcp) do {            \
        mtx_assert(&(__mcp)->lock, MA_OWNED);   \
        (__mcp)->flags &= ~DPAA2_PORTAL_LOCKED; \
        mtx_unlock(&(__mcp)->lock);             \
} while (0)

enum dpaa2_rc_region_type {
        DPAA2_RC_REG_MC_PORTAL,
        DPAA2_RC_REG_QBMAN_PORTAL
};

/**
 * @brief Helper object to interact with the MC portal.
 *
 * res:                 Unmapped portal's I/O memory.
 * map:                 Mapped portal's I/O memory.
 * lock:                Lock to send a command to the portal and wait for the
 *                      result.
 * flags:               Current state of the object.
 * rc_api_major:        Major version of the DPRC API.
 * rc_api_minor:        Minor version of the DPRC API.
 */
struct dpaa2_mcp {
        struct resource *res;
        struct resource_map *map;
        struct mtx      lock;
        uint16_t        flags;
        uint16_t        rc_api_major;
        uint16_t        rc_api_minor;
};

/**
 * @brief Command object holds data to be written to the MC portal.
 *
 * header:      8 least significant bytes of the MC portal.
 * params:      Parameters to pass together with the command to MC. Might keep
 *              command execution results.
 *
 * NOTE: 64 bytes.
 */
struct dpaa2_cmd {
        uint64_t        header;
        uint64_t        params[DPAA2_CMD_PARAMS_N];
};

/**
 * @brief Helper object to access fields of the MC command header.
 *
 * srcid:       The SoC architected source ID of the submitter. This field is
 *              reserved and cannot be written by the driver.
 * flags_hw:    Bits from 8 to 15 of the command header. Most of them are
 *              reserved at the moment.
 * status:      Command ready/status. This field is used as the handshake field
 *              between MC and the driver. MC reports command completion with
 *              success/error codes in this field.
 * flags_sw:    ...
 * token:       ...
 * cmdid:       ...
 *
 * NOTE: 8 bytes.
 */
struct dpaa2_cmd_header {
        uint8_t         srcid;
        uint8_t         flags_hw;
        uint8_t         status;
        uint8_t         flags_sw;
        uint16_t        token;
        uint16_t        cmdid;
} __packed;

/**
 * @brief Information about DPAA2 object.
 *
 * id:          ID of a logical object resource.
 * vendor:      Object vendor identifier.
 * irq_count:   Number of interrupts supported by the object.
 * reg_count:   Number of mappable regions supported by the object.
 * state:       Object state (combination of states).
 * ver_major:   Major version of the object.
 * ver_minor:   Minor version of the object.
 * flags:       Object attributes flags.
 * type:        ...
 * label:       ...
 */
struct dpaa2_obj {
        uint32_t        id;
        uint16_t        vendor;
        uint8_t         irq_count;
        uint8_t         reg_count;
        uint32_t        state;
        uint16_t        ver_major;
        uint16_t        ver_minor;
        uint16_t        flags;
        uint8_t         label[DPAA2_LABEL_SZ];
        enum dpaa2_dev_type type;
};

/**
 * @brief Attributes of the DPRC object.
 *
 * cont_id:     Container ID.
 * portal_id:   Container's portal ID.
 * options:     Container's options as set at container's creation.
 * icid:        Container's isolation context ID.
 */
struct dpaa2_rc_attr {
        uint32_t        cont_id;
        uint32_t        portal_id;
        uint32_t        options;
        uint32_t        icid;
};

/**
 * @brief Description of the object's memory region.
 *
 * base_paddr:  Region base physical address.
 * base_offset: Region base offset.
 * size:        Region size (in bytes).
 * flags:       Region flags (cacheable, etc.)
 * type:        Type of a software portal this region belongs to.
 */
struct dpaa2_rc_obj_region {
        uint64_t        base_paddr;
        uint64_t        base_offset;
        uint32_t        size;
        uint32_t        flags;
        enum dpaa2_rc_region_type type;
};

/**
 * @brief DPAA2 endpoint descriptor.
 *
 * obj_id:      Endpoint object ID.
 * if_id:       Interface ID; for endpoints with multiple interfaces
 *              (DPSW, DPDMUX), 0 - otherwise.
 * type:        Endpoint object type, null-terminated string.
 */
struct dpaa2_ep_desc {
        uint32_t        obj_id;
        uint32_t        if_id;
        enum dpaa2_dev_type type;
};

/**
 * @brief Configuration of the channel data availability notification (CDAN).
 *
 * qman_ctx:    Context value provided with each CDAN message.
 * dpio_id:     DPIO object ID configured with a notification channel.
 * prior:       Priority selection within the DPIO channel; valid values
 *              are 0-7, depending on the number of priorities in that channel.
 */
struct dpaa2_con_notif_cfg {
        uint64_t        qman_ctx;
        uint32_t        dpio_id;
        uint8_t         prior;
};

/**
 * @brief Attributes of the DPMCP object.
 *
 * id:           DPMCP object ID.
 * options:      Options of the MC portal (disabled high-prio commands, etc.).
 */
struct dpaa2_mcp_attr {
        uint32_t                id;
        uint32_t                options;
};

/**
 * @brief Software context for the DPAA2 MC portal.
 */
struct dpaa2_mcp_softc {
        device_t                 dev;
        struct dpaa2_mcp_attr    attr;

        struct resource         *res[DPAA2_MCP_MAX_RESOURCES];
        struct resource_map      map[DPAA2_MCP_MAX_RESOURCES];
};

int     dpaa2_mcp_init_portal(struct dpaa2_mcp **mcp, struct resource *res,
            struct resource_map *map, uint16_t flags);
void    dpaa2_mcp_free_portal(struct dpaa2_mcp *mcp);

/* to quickly update command token */
struct dpaa2_cmd *dpaa2_mcp_tk(struct dpaa2_cmd *cmd, const uint16_t token);
/* to quickly update command flags */
struct dpaa2_cmd *dpaa2_mcp_f(struct dpaa2_cmd *cmd, const uint16_t flags);

#define DPAA2_CMD_INIT_FLAGS(__cmd, __flags) do {                       \
        KASSERT((__cmd) != NULL, ("%s:%d: failed", __func__, __LINE__)); \
        struct dpaa2_cmd_header *__hdr;                                 \
        uint32_t __dcpi;                                                \
                                                                        \
        __hdr = (struct dpaa2_cmd_header *)&((__cmd)->header);          \
        __hdr->srcid = 0;                                               \
        __hdr->status = DPAA2_CMD_STAT_OK;                              \
        __hdr->token = 0;                                               \
        __hdr->cmdid = 0;                                               \
        __hdr->flags_hw = DPAA2_CMD_DEF;                                \
        __hdr->flags_sw = DPAA2_CMD_DEF;                                \
        if ((__flags) & DPAA2_CMD_HIGH_PRIO) {                          \
                __hdr->flags_hw |= DPAA2_HW_FLAG_HIGH_PRIO;             \
        }                                                               \
        if ((__flags) & DPAA2_CMD_INTR_DIS) {                           \
                __hdr->flags_sw |= DPAA2_SW_FLAG_INTR_DIS;              \
        }                                                               \
        for (__dcpi = 0; __dcpi < DPAA2_CMD_PARAMS_N; __dcpi++) {       \
                (__cmd)->params[__dcpi] = 0;                            \
        }                                                               \
} while (0)
#define DPAA2_CMD_INIT(c)       DPAA2_CMD_INIT_FLAGS((c), DPAA2_CMD_DEF)
#define DPAA2_CMD_TK(c, t)      dpaa2_mcp_tk((c), (t))
#define DPAA2_CMD_F(c, f)       dpaa2_mcp_f((c), (f))

#endif /* _DPAA2_MCP_H */