root/sys/dev/qat/qat_common/adf_freebsd_admin.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
#include "qat_freebsd.h"
#include "adf_cfg.h"
#include "adf_common_drv.h"
#include "adf_accel_devices.h"
#include "icp_qat_uclo.h"
#include "icp_qat_fw.h"
#include "icp_qat_fw_init_admin.h"
#include "adf_cfg_strings.h"
#include "adf_transport_access_macros.h"
#include "adf_transport_internal.h"
#include "adf_heartbeat.h"
#include <sys/types.h>
#include <sys/lock.h>
#include <sys/sx.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <dev/pci/pcivar.h>
#include <machine/bus_dma.h>

#include <linux/delay.h>

#define ADF_CONST_TABLE_VERSION_BYTE (0)
/* Keep version number in range 0-255 */
#define ADF_CONST_TABLE_VERSION (1)

/* Admin Messages Registers */
#define ADF_MAILBOX_STRIDE 0x1000
#define ADF_ADMINMSG_LEN 32
#define FREEBSD_ALLIGNMENT_SIZE 64
#define ADF_INIT_CONFIG_SIZE 1024

static u8 const_tab[1024] __aligned(1024) = {
ADF_CONST_TABLE_VERSION,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76,
0x54, 0x32, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab,
0x89, 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x05, 0x9e,
0xd8, 0x36, 0x7c, 0xd5, 0x07, 0x30, 0x70, 0xdd, 0x17, 0xf7, 0x0e, 0x59, 0x39,
0xff, 0xc0, 0x0b, 0x31, 0x68, 0x58, 0x15, 0x11, 0x64, 0xf9, 0x8f, 0xa7, 0xbe,
0xfa, 0x4f, 0xa4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae,
0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f,
0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29,
0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, 0xdd, 0x17,
0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, 0x33, 0x26, 0x67, 0xff,
0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c,
0x2e, 0x0d, 0x64, 0xf9, 0x8f, 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f,
0xa4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb,
0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94,
0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, 0x0e, 0x52,
0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13,
0x7e, 0x21, 0x79, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define ADF_ADMIN_POLL_INTERVAL_US 20
#define ADF_ADMIN_POLL_RETRIES 5000

static void
dma_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
        bus_addr_t *addr;

        addr = arg;
        if (error == 0 && nseg == 1)
                *addr = segs[0].ds_addr;
        else
                *addr = 0;
}

int
adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev,
                       u32 ae,
                       void *in,
                       void *out)
{
        struct adf_admin_comms *admin = accel_dev->admin;
        struct adf_hw_device_data *hw_data = accel_dev->hw_device;
        struct resource *mailbox = admin->mailbox_addr;
        struct admin_info admin_csrs_info;

        hw_data->get_admin_info(&admin_csrs_info);
        int offset = ae * ADF_ADMINMSG_LEN * 2;
        int mb_offset =
            ae * ADF_MAILBOX_STRIDE + admin_csrs_info.mailbox_offset;

        int times, received;
        struct icp_qat_fw_init_admin_req *request = in;

        sx_xlock(&admin->lock);

        if (ADF_CSR_RD(mailbox, mb_offset) == 1) {
                sx_xunlock(&admin->lock);
                return EAGAIN;
        }

        memcpy(admin->virt_addr + offset, in, ADF_ADMINMSG_LEN);
        ADF_CSR_WR(mailbox, mb_offset, 1);
        received = 0;
        for (times = 0; times < ADF_ADMIN_POLL_RETRIES; times++) {
                usleep_range(ADF_ADMIN_POLL_INTERVAL_US,
                             ADF_ADMIN_POLL_INTERVAL_US * 2);
                if (ADF_CSR_RD(mailbox, mb_offset) == 0) {
                        received = 1;
                        break;
                }
        }
        if (received)
                memcpy(out,
                       admin->virt_addr + offset + ADF_ADMINMSG_LEN,
                       ADF_ADMINMSG_LEN);
        else
                device_printf(GET_DEV(accel_dev),
                              "Failed to send admin msg %d to accelerator %d\n",
                              request->cmd_id,
                              ae);

        sx_xunlock(&admin->lock);
        return received ? 0 : EFAULT;
}

static inline int
adf_set_dc_ibuf(struct adf_accel_dev *accel_dev,
                struct icp_qat_fw_init_admin_req *req)
{
        char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
        unsigned long ibuf_size = 0;

        if (!adf_cfg_get_param_value(
                accel_dev, ADF_GENERAL_SEC, ADF_INTER_BUF_SIZE, val)) {
                if (compat_strtoul(val, 0, &ibuf_size))
                        return EFAULT;
        }

        if (ibuf_size != 32 && ibuf_size != 64)
                ibuf_size = 64;

        req->ibuf_size_in_kb = ibuf_size;

        return 0;
}

int
adf_send_admin(struct adf_accel_dev *accel_dev,
               struct icp_qat_fw_init_admin_req *req,
               struct icp_qat_fw_init_admin_resp *resp,
               u32 ae_mask)
{
        int i;
        unsigned int mask;

        for (i = 0, mask = ae_mask; mask; i++, mask >>= 1) {
                if (!(mask & 1))
                        continue;
                if (adf_put_admin_msg_sync(accel_dev, i, req, resp) ||
                    resp->status)
                        return EFAULT;
        }

        return 0;
}

static int
adf_init_me(struct adf_accel_dev *accel_dev)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp resp;
        struct adf_hw_device_data *hw_device = accel_dev->hw_device;
        u32 ae_mask = hw_device->ae_mask;

        explicit_bzero(&req, sizeof(req));
        explicit_bzero(&resp, sizeof(resp));
        req.cmd_id = ICP_QAT_FW_INIT_ME;

        if (adf_set_dc_ibuf(accel_dev, &req))
                return EFAULT;
        if (accel_dev->aram_info) {
                req.init_cfg_sz = sizeof(*accel_dev->aram_info);
                req.init_cfg_ptr = (u64)accel_dev->admin->aram_map_phys_addr;
        }
        if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
                return EFAULT;

        return 0;
}

static int
adf_set_heartbeat_timer(struct adf_accel_dev *accel_dev)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp resp;
        struct adf_hw_device_data *hw_device = accel_dev->hw_device;
        u32 ae_mask = hw_device->ae_mask;
        u32 heartbeat_ticks;

        explicit_bzero(&req, sizeof(req));
        req.cmd_id = ICP_QAT_FW_HEARTBEAT_TIMER_SET;
        req.hb_cfg_ptr = accel_dev->admin->phy_hb_addr;
        if (adf_get_hb_timer(accel_dev, &heartbeat_ticks))
                return EINVAL;
        req.heartbeat_ticks = heartbeat_ticks;

        if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
                return EFAULT;

        return 0;
}

static int
adf_get_dc_capabilities(struct adf_accel_dev *accel_dev, u32 *capabilities)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp resp;
        u32 ae_mask = 1;

        explicit_bzero(&req, sizeof(req));
        req.cmd_id = ICP_QAT_FW_COMP_CAPABILITY_GET;

        if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
                return EFAULT;

        *capabilities = resp.extended_features;

        return 0;
}

static int
adf_set_fw_constants(struct adf_accel_dev *accel_dev)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp resp;
        struct adf_hw_device_data *hw_device = accel_dev->hw_device;
        u32 ae_mask = hw_device->admin_ae_mask;

        explicit_bzero(&req, sizeof(req));
        req.cmd_id = ICP_QAT_FW_CONSTANTS_CFG;

        req.init_cfg_sz = sizeof(const_tab);
        req.init_cfg_ptr = accel_dev->admin->const_tbl_addr;

        if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
                return EFAULT;

        return 0;
}

static int
adf_get_fw_status(struct adf_accel_dev *accel_dev,
                  u8 *major,
                  u8 *minor,
                  u8 *patch)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp resp;
        u32 ae_mask = 1;

        explicit_bzero(&req, sizeof(req));
        req.cmd_id = ICP_QAT_FW_STATUS_GET;

        if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
                return EFAULT;

        *major = resp.version_major_num;
        *minor = resp.version_minor_num;
        *patch = resp.version_patch_num;

        return 0;
}

int
adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp)
{
        struct icp_qat_fw_init_admin_req req;
        struct icp_qat_fw_init_admin_resp rsp;
        unsigned int ae_mask = 1;

        if (!accel_dev || !timestamp)
                return EFAULT;

        explicit_bzero(&req, sizeof(req));
        req.cmd_id = ICP_QAT_FW_TIMER_GET;

        if (adf_send_admin(accel_dev, &req, &rsp, ae_mask))
                return EFAULT;

        *timestamp = rsp.timestamp;
        return 0;
}

int
adf_get_fw_pke_stats(struct adf_accel_dev *accel_dev,
                     u64 *suc_count,
                     u64 *unsuc_count)
{
        struct icp_qat_fw_init_admin_req req = { 0 };
        struct icp_qat_fw_init_admin_resp resp = { 0 };
        unsigned long sym_ae_msk = 0;
        u8 sym_ae_msk_size = 0;
        u8 i = 0;

        if (!suc_count || !unsuc_count)
                return EFAULT;

        sym_ae_msk = accel_dev->au_info->sym_ae_msk;
        sym_ae_msk_size =
            sizeof(accel_dev->au_info->sym_ae_msk) * BITS_PER_BYTE;

        req.cmd_id = ICP_QAT_FW_PKE_REPLAY_STATS_GET;
        for_each_set_bit(i, &sym_ae_msk, sym_ae_msk_size)
        {
                memset(&resp, 0, sizeof(struct icp_qat_fw_init_admin_resp));
                if (adf_put_admin_msg_sync(accel_dev, i, &req, &resp) ||
                    resp.status) {
                        return EFAULT;
                }
                *suc_count += resp.successful_count;
                *unsuc_count += resp.unsuccessful_count;
        }
        return 0;
}

/**
 * adf_send_admin_init() - Function sends init message to FW
 * @accel_dev: Pointer to acceleration device.
 *
 * Function sends admin init message to the FW
 *
 * Return: 0 on success, error code otherwise.
 */
int
adf_send_admin_init(struct adf_accel_dev *accel_dev)
{
        int ret;
        u32 dc_capabilities = 0;
        unsigned int storage_enabled = 0;

        if (GET_HW_DATA(accel_dev)->query_storage_cap) {
                ret = adf_get_dc_capabilities(accel_dev, &dc_capabilities);
                if (ret) {
                        device_printf(GET_DEV(accel_dev),
                                      "Cannot get dc capabilities\n");
                        return ret;
                }
                accel_dev->hw_device->extended_dc_capabilities =
                    dc_capabilities;
        } else {
                ret = GET_HW_DATA(accel_dev)->get_storage_enabled(
                    accel_dev, &storage_enabled);
                if (ret) {
                        device_printf(GET_DEV(accel_dev),
                                      "Cannot get storage enabled\n");
                        return ret;
                }
        }

        ret = adf_set_heartbeat_timer(accel_dev);
        if (ret) {
                if (ret == EINVAL) {
                        device_printf(GET_DEV(accel_dev),
                                      "Cannot set heartbeat timer\n");
                        return ret;
                }
                device_printf(GET_DEV(accel_dev),
                              "Heartbeat is not supported\n");
        }

        ret = adf_get_fw_status(accel_dev,
                                &accel_dev->fw_versions.fw_version_major,
                                &accel_dev->fw_versions.fw_version_minor,
                                &accel_dev->fw_versions.fw_version_patch);
        if (ret) {
                device_printf(GET_DEV(accel_dev), "Cannot get fw version\n");
                return ret;
        }

        device_printf(GET_DEV(accel_dev),
                      "FW version: %d.%d.%d\n",
                      accel_dev->fw_versions.fw_version_major,
                      accel_dev->fw_versions.fw_version_minor,
                      accel_dev->fw_versions.fw_version_patch);

        ret = adf_set_fw_constants(accel_dev);
        if (ret) {
                device_printf(GET_DEV(accel_dev), "Cannot set fw constants\n");
                return ret;
        }

        ret = adf_init_me(accel_dev);
        if (ret)
                device_printf(GET_DEV(accel_dev), "Cannot init AE\n");

        return ret;
}

int
adf_init_admin_comms(struct adf_accel_dev *accel_dev)
{
        struct adf_admin_comms *admin = NULL;
        struct adf_hw_device_data *hw_data = NULL;
        struct adf_bar *pmisc = NULL;
        struct resource *csr = NULL;
        struct admin_info admin_csrs_info;
        unsigned int adminmsg_u, adminmsg_l;
        u64 reg_val = 0;
        int ret = 0;

        admin = kzalloc_node(sizeof(*accel_dev->admin),
                             M_WAITOK | M_ZERO,
                             dev_to_node(GET_DEV(accel_dev)));
        hw_data = accel_dev->hw_device;
        pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
        csr = pmisc->virt_addr;
        ret = bus_dma_mem_create(&admin->dma_mem,
                                 accel_dev->dma_tag,
                                 FREEBSD_ALLIGNMENT_SIZE,
                                 BUS_SPACE_MAXADDR,
                                 PAGE_SIZE,
                                 0);
        if (ret != 0) {
                device_printf(GET_DEV(accel_dev),
                              "Failed to allocate dma buff\n");
                kfree(admin);
                return ret;
        }
        admin->virt_addr = admin->dma_mem.dma_vaddr;
        admin->phy_addr = admin->dma_mem.dma_baddr;
        bzero(admin->virt_addr, PAGE_SIZE);

        ret = bus_dmamap_create(accel_dev->dma_tag, 0, &admin->const_tbl_map);
        if (ret != 0) {
                device_printf(GET_DEV(accel_dev), "Failed to create DMA map\n");
                bus_dma_mem_free(&admin->dma_mem);
                kfree(admin);
                return ret;
        }

        ret = bus_dmamap_load(accel_dev->dma_tag,
                              admin->const_tbl_map,
                              (void *)const_tab,
                              1024,
                              dma_callback,
                              &admin->const_tbl_addr,
                              BUS_DMA_NOWAIT);
        if (ret == 0 && admin->const_tbl_addr == 0)
                ret = EFBIG;
        if (ret != 0) {
                device_printf(GET_DEV(accel_dev),
                              "Failed to map const table for DMA\n");
                bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
                bus_dma_mem_free(&admin->dma_mem);
                kfree(admin);
                return ret;
        }

        /* DMA ARAM address map */
        if (accel_dev->aram_info) {
                ret =
                    bus_dmamap_create(accel_dev->dma_tag, 0, &admin->aram_map);
                if (ret != 0) {
                        device_printf(GET_DEV(accel_dev),
                                      "Failed to create DMA map\n");
                        bus_dma_mem_free(&admin->dma_mem);
                        kfree(admin);
                        return ret;
                }
                ret = bus_dmamap_load(accel_dev->dma_tag,
                                      admin->aram_map,
                                      (void *)accel_dev->aram_info,
                                      sizeof(*accel_dev->aram_info),
                                      dma_callback,
                                      &admin->aram_map_phys_addr,
                                      BUS_DMA_NOWAIT);

                if (ret == 0 && admin->aram_map_phys_addr == 0)
                        ret = EFBIG;
                if (ret != 0) {
                        device_printf(GET_DEV(accel_dev),
                                      "Failed to map aram phys addr for DMA\n");
                        bus_dmamap_destroy(accel_dev->dma_tag, admin->aram_map);
                        bus_dma_mem_free(&admin->dma_mem);
                        kfree(admin);
                        return ret;
                }
        }

        ret = bus_dma_mem_create(&admin->dma_hb,
                                 accel_dev->dma_tag,
                                 FREEBSD_ALLIGNMENT_SIZE,
                                 BUS_SPACE_MAXADDR,
                                 PAGE_SIZE,
                                 0);
        if (ret != 0) {
                device_printf(GET_DEV(accel_dev),
                              "Failed to allocate dma buff\n");
                bus_dmamap_unload(accel_dev->dma_tag, admin->const_tbl_map);
                bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
                bus_dma_mem_free(&admin->dma_mem);
                kfree(admin);
                return ret;
        }

        admin->virt_hb_addr = admin->dma_hb.dma_vaddr;
        admin->phy_hb_addr = admin->dma_hb.dma_baddr;
        bzero(admin->virt_hb_addr, PAGE_SIZE);

        hw_data->get_admin_info(&admin_csrs_info);

        adminmsg_u = admin_csrs_info.admin_msg_ur;
        adminmsg_l = admin_csrs_info.admin_msg_lr;
        reg_val = (u64)admin->phy_addr;
        ADF_CSR_WR(csr, adminmsg_u, reg_val >> 32);
        ADF_CSR_WR(csr, adminmsg_l, reg_val);
        sx_init(&admin->lock, "qat admin");
        admin->mailbox_addr = csr;
        accel_dev->admin = admin;
        return 0;
}

void
adf_exit_admin_comms(struct adf_accel_dev *accel_dev)
{
        struct adf_admin_comms *admin = accel_dev->admin;

        if (!admin)
                return;

        if (admin->virt_addr)
                bus_dma_mem_free(&admin->dma_mem);

        if (admin->virt_hb_addr)
                bus_dma_mem_free(&admin->dma_hb);

        bus_dmamap_unload(accel_dev->dma_tag, admin->const_tbl_map);
        bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
        sx_destroy(&admin->lock);
        kfree(admin);
        accel_dev->admin = NULL;
}