root/usr/src/uts/common/io/hxge/hpi_rxdma.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <hpi_rxdma.h>
#include <hxge_common.h>
#include <hxge_impl.h>

#define  RXDMA_RESET_TRY_COUNT  5
#define  RXDMA_RESET_DELAY      5

#define  RXDMA_OP_DISABLE       0
#define  RXDMA_OP_ENABLE        1
#define  RXDMA_OP_RESET         2

#define  RCR_TIMEOUT_ENABLE     1
#define  RCR_TIMEOUT_DISABLE    2
#define  RCR_THRESHOLD          4

hpi_status_t
hpi_rxdma_cfg_logical_page_handle(hpi_handle_t handle, uint8_t rdc,
    uint64_t page_handle)
{
        rdc_page_handle_t page_hdl;

        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "rxdma_cfg_logical_page_handle"
                    " Illegal RDC number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        page_hdl.value = 0;
        page_hdl.bits.handle = (uint32_t)page_handle;

        RXDMA_REG_WRITE64(handle, RDC_PAGE_HANDLE, rdc, page_hdl.value);

        return (HPI_SUCCESS);
}

hpi_status_t
hpi_rxdma_cfg_rdc_wait_for_qst(hpi_handle_t handle, uint8_t rdc)
{
        rdc_rx_cfg1_t   cfg;
        uint32_t        count = RXDMA_RESET_TRY_COUNT;
        uint32_t        delay_time = RXDMA_RESET_DELAY;

        RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);

        while ((count--) && (cfg.bits.qst == 0)) {
                HXGE_DELAY(delay_time);
                RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
        }

        if (cfg.bits.qst == 0)
                return (HPI_FAILURE);

        return (HPI_SUCCESS);
}

/* RX DMA functions */
static hpi_status_t
hpi_rxdma_cfg_rdc_ctl(hpi_handle_t handle, uint8_t rdc, uint8_t op)
{
        rdc_rx_cfg1_t cfg;
        uint32_t count = RXDMA_RESET_TRY_COUNT;
        uint32_t delay_time = RXDMA_RESET_DELAY;
        uint32_t error = HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RESET_ERR, rdc);

        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_cfg_rdc_ctl Illegal RDC number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        switch (op) {
        case RXDMA_OP_ENABLE:
                RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
                cfg.bits.enable = 1;
                RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);

                HXGE_DELAY(delay_time);
                RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);

                while ((count--) && (cfg.bits.qst == 1)) {
                        HXGE_DELAY(delay_time);
                        RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
                }
                if (cfg.bits.qst == 1) {
                        return (HPI_FAILURE);
                }
                break;

        case RXDMA_OP_DISABLE:
                RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
                cfg.bits.enable = 0;
                RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);

                HXGE_DELAY(delay_time);
                if (hpi_rxdma_cfg_rdc_wait_for_qst(handle,
                    rdc) != HPI_SUCCESS) {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " hpi_rxdma_cfg_rdc_ctl"
                            " RXDMA_OP_DISABLE Failed for RDC %d \n",
                            rdc));
                        return (error);
                }
                break;

        case RXDMA_OP_RESET:
                cfg.value = 0;
                cfg.bits.reset = 1;
                RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);
                HXGE_DELAY(delay_time);
                RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);

                while ((count--) && (cfg.bits.qst == 0)) {
                        HXGE_DELAY(delay_time);
                        RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
                }
                if (count == 0) {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " hpi_rxdma_cfg_rdc_ctl"
                            " Reset Failed for RDC %d \n", rdc));
                        return (error);
                }
                break;

        default:
                return (HPI_RXDMA_SW_PARAM_ERROR);
        }

        return (HPI_SUCCESS);
}

hpi_status_t
hpi_rxdma_cfg_rdc_enable(hpi_handle_t handle, uint8_t rdc)
{
        return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_ENABLE));
}

hpi_status_t
hpi_rxdma_cfg_rdc_disable(hpi_handle_t handle, uint8_t rdc)
{
        return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_DISABLE));
}

hpi_status_t
hpi_rxdma_cfg_rdc_reset(hpi_handle_t handle, uint8_t rdc)
{
        return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_RESET));
}

static hpi_status_t
hpi_rxdma_cfg_rdc_rcr_ctl(hpi_handle_t handle, uint8_t rdc,
    uint8_t op, uint16_t param)
{
        rdc_rcr_cfg_b_t rcr_cfgb;

        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "rxdma_cfg_rdc_rcr_ctl Illegal RDC number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        RXDMA_REG_READ64(handle, RDC_RCR_CFG_B, rdc, &rcr_cfgb.value);

        switch (op) {
        case RCR_TIMEOUT_ENABLE:
                rcr_cfgb.bits.timeout = (uint8_t)param;
                rcr_cfgb.bits.entout = 1;
                break;

        case RCR_THRESHOLD:
                rcr_cfgb.bits.pthres = param;
                break;

        case RCR_TIMEOUT_DISABLE:
                rcr_cfgb.bits.entout = 0;
                break;

        default:
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "rxdma_cfg_rdc_rcr_ctl Illegal opcode %x \n", op));
                return (HPI_RXDMA_OPCODE_INVALID(rdc));
        }

        RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value);
        return (HPI_SUCCESS);
}

hpi_status_t
hpi_rxdma_cfg_rdc_rcr_threshold(hpi_handle_t handle, uint8_t rdc,
    uint16_t rcr_threshold)
{
        return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc,
            RCR_THRESHOLD, rcr_threshold));
}

hpi_status_t
hpi_rxdma_cfg_rdc_rcr_timeout(hpi_handle_t handle, uint8_t rdc,
    uint8_t rcr_timeout)
{
        return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc,
            RCR_TIMEOUT_ENABLE, rcr_timeout));
}

/*
 * Configure The RDC channel Rcv Buffer Ring
 */
hpi_status_t
hpi_rxdma_cfg_rdc_ring(hpi_handle_t handle, uint8_t rdc,
    rdc_desc_cfg_t *rdc_desc_cfg)
{
        rdc_rbr_cfg_a_t         cfga;
        rdc_rbr_cfg_b_t         cfgb;
        rdc_rx_cfg1_t           cfg1;
        rdc_rx_cfg2_t           cfg2;
        rdc_rcr_cfg_a_t         rcr_cfga;
        rdc_rcr_cfg_b_t         rcr_cfgb;
        rdc_page_handle_t       page_handle;

        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "rxdma_cfg_rdc_ring Illegal RDC number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        cfga.value = 0;
        cfgb.value = 0;
        cfg1.value = 0;
        cfg2.value = 0;
        page_handle.value = 0;

        if (rdc_desc_cfg->mbox_enable == 1) {
                cfg1.bits.mbaddr_h = (rdc_desc_cfg->mbox_addr >> 32) & 0xfff;
                cfg2.bits.mbaddr_l = ((rdc_desc_cfg->mbox_addr &
                    RXDMA_CFIG2_MBADDR_L_MASK) >> RXDMA_CFIG2_MBADDR_L_SHIFT);

                /*
                 * Only after all the configurations are set, then
                 * enable the RDC or else configuration fatal error
                 * will be returned (especially if the Hypervisor
                 * set up the logical pages with non-zero values.
                 * This HPI function only sets up the configuration.
                 * Call the enable function to enable the RDMC!
                 */
        }

        if (rdc_desc_cfg->full_hdr == 1)
                cfg2.bits.full_hdr = 1;

        if (RXDMA_BUFF_OFFSET_VALID(rdc_desc_cfg->offset)) {
                cfg2.bits.offset = rdc_desc_cfg->offset;
        } else {
                cfg2.bits.offset = SW_OFFSET_NO_OFFSET;
        }

        /* rbr config */
        cfga.value = (rdc_desc_cfg->rbr_addr &
            (RBR_CFIG_A_STDADDR_MASK | RBR_CFIG_A_STDADDR_BASE_MASK));

        /* The remaining 20 bits in the DMA address form the handle */
        page_handle.bits.handle = (rdc_desc_cfg->rbr_addr >> 44) && 0xfffff;

        /*
         * The RBR ring size must be multiple of 64.
         */
        if ((rdc_desc_cfg->rbr_len < RBR_DEFAULT_MIN_LEN) ||
            (rdc_desc_cfg->rbr_len > RBR_DEFAULT_MAX_LEN) ||
            (rdc_desc_cfg->rbr_len % 64)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_cfg_rdc_ring Illegal RBR Queue Length %d \n",
                    rdc_desc_cfg->rbr_len));
                return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RBRSZIE_INVALID, rdc));
        }

        /*
         * The lower 6 bits are hardcoded to 0 and the higher 10 bits are
         * stored in len.
         */
        cfga.bits.len = rdc_desc_cfg->rbr_len >> 6;
        HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL,
            "hpi_rxdma_cfg_rdc_ring CFGA 0x%llx len %d (RBR LEN %d)\n",
            cfga.value, cfga.bits.len, rdc_desc_cfg->rbr_len));

        /*
         * bksize is 1 bit
         * Buffer Block Size. b0 - 4K; b1 - 8K.
         */
        if (rdc_desc_cfg->page_size == SIZE_4KB)
                cfgb.bits.bksize = RBR_BKSIZE_4K;
        else if (rdc_desc_cfg->page_size == SIZE_8KB)
                cfgb.bits.bksize = RBR_BKSIZE_8K;
        else {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "rxdma_cfg_rdc_ring blksize: Illegal buffer size %d \n",
                    rdc_desc_cfg->page_size));
                return (HPI_RXDMA_BUFSZIE_INVALID);
        }

        /*
         * Size 0 of packet buffer. b00 - 256; b01 - 512; b10 - 1K; b11 - resvd.
         */
        if (rdc_desc_cfg->valid0) {
                if (rdc_desc_cfg->size0 == SIZE_256B)
                        cfgb.bits.bufsz0 = RBR_BUFSZ0_256B;
                else if (rdc_desc_cfg->size0 == SIZE_512B)
                        cfgb.bits.bufsz0 = RBR_BUFSZ0_512B;
                else if (rdc_desc_cfg->size0 == SIZE_1KB)
                        cfgb.bits.bufsz0 = RBR_BUFSZ0_1K;
                else {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " rxdma_cfg_rdc_ring"
                            " blksize0: Illegal buffer size %x \n",
                            rdc_desc_cfg->size0));
                        return (HPI_RXDMA_BUFSZIE_INVALID);
                }
                cfgb.bits.vld0 = 1;
        } else {
                cfgb.bits.vld0 = 0;
        }

        /*
         * Size 1 of packet buffer. b0 - 1K; b1 - 2K.
         */
        if (rdc_desc_cfg->valid1) {
                if (rdc_desc_cfg->size1 == SIZE_1KB)
                        cfgb.bits.bufsz1 = RBR_BUFSZ1_1K;
                else if (rdc_desc_cfg->size1 == SIZE_2KB)
                        cfgb.bits.bufsz1 = RBR_BUFSZ1_2K;
                else {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " rxdma_cfg_rdc_ring"
                            " blksize1: Illegal buffer size %x \n",
                            rdc_desc_cfg->size1));
                        return (HPI_RXDMA_BUFSZIE_INVALID);
                }
                cfgb.bits.vld1 = 1;
        } else {
                cfgb.bits.vld1 = 0;
        }

        /*
         * Size 2 of packet buffer. b0 - 2K; b1 - 4K.
         */
        if (rdc_desc_cfg->valid2) {
                if (rdc_desc_cfg->size2 == SIZE_2KB)
                        cfgb.bits.bufsz2 = RBR_BUFSZ2_2K;
                else if (rdc_desc_cfg->size2 == SIZE_4KB)
                        cfgb.bits.bufsz2 = RBR_BUFSZ2_4K;
                else {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " rxdma_cfg_rdc_ring"
                            " blksize2: Illegal buffer size %x \n",
                            rdc_desc_cfg->size2));
                        return (HPI_RXDMA_BUFSZIE_INVALID);
                }
                cfgb.bits.vld2 = 1;
        } else {
                cfgb.bits.vld2 = 0;
        }

        rcr_cfga.value = (rdc_desc_cfg->rcr_addr &
            (RCRCFIG_A_STADDR_MASK | RCRCFIG_A_STADDR_BASE_MASK));

        /*
         * The rcr len must be multiple of 32.
         */
        if ((rdc_desc_cfg->rcr_len < RCR_DEFAULT_MIN_LEN) ||
            (rdc_desc_cfg->rcr_len > HXGE_RCR_MAX) ||
            (rdc_desc_cfg->rcr_len % 32)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    " rxdma_cfg_rdc_ring Illegal RCR Queue Length %d \n",
                    rdc_desc_cfg->rcr_len));
                return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RCRSZIE_INVALID, rdc));
        }

        /*
         * Bits 15:5 of the maximum number of 8B entries in RCR.  Bits 4:0 are
         * hard-coded to zero.  The maximum size is 2^16 - 32.
         */
        rcr_cfga.bits.len = rdc_desc_cfg->rcr_len >> 5;

        rcr_cfgb.value = 0;
        if (rdc_desc_cfg->rcr_timeout_enable == 1) {
                /* check if the rcr timeout value is valid */

                if (RXDMA_RCR_TO_VALID(rdc_desc_cfg->rcr_timeout)) {
                        rcr_cfgb.bits.timeout = rdc_desc_cfg->rcr_timeout;
                        rcr_cfgb.bits.entout = 1;
                } else {
                        HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                            " rxdma_cfg_rdc_ring"
                            " Illegal RCR Timeout value %d \n",
                            rdc_desc_cfg->rcr_timeout));
                        rcr_cfgb.bits.entout = 0;
                }
        } else {
                rcr_cfgb.bits.entout = 0;
        }

        /* check if the rcr threshold value is valid */
        if (RXDMA_RCR_THRESH_VALID(rdc_desc_cfg->rcr_threshold)) {
                rcr_cfgb.bits.pthres = rdc_desc_cfg->rcr_threshold;
        } else {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    " rxdma_cfg_rdc_ring Illegal RCR Threshold value %d \n",
                    rdc_desc_cfg->rcr_threshold));
                rcr_cfgb.bits.pthres = 1;
        }

        /* now do the actual HW configuration */
        RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg1.value);
        RXDMA_REG_WRITE64(handle, RDC_RX_CFG2, rdc, cfg2.value);

        RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_A, rdc, cfga.value);
        RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_B, rdc, cfgb.value);

        RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_A, rdc, rcr_cfga.value);
        RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value);

        RXDMA_REG_WRITE64(handle, RDC_PAGE_HANDLE, rdc, page_handle.value);

        return (HPI_SUCCESS);
}

hpi_status_t
hpi_rxdma_ring_perr_stat_get(hpi_handle_t handle,
    rdc_pref_par_log_t *pre_log, rdc_pref_par_log_t *sha_log)
{
        /*
         * Hydra doesn't have details about these errors.
         * It only provides the addresses of the errors.
         */
        HXGE_REG_RD64(handle, RDC_PREF_PAR_LOG, &pre_log->value);
        HXGE_REG_RD64(handle, RDC_SHADOW_PAR_LOG, &sha_log->value);

        return (HPI_SUCCESS);
}


/* system wide conf functions */

hpi_status_t
hpi_rxdma_cfg_clock_div_set(hpi_handle_t handle, uint16_t count)
{
        uint64_t        offset;
        rdc_clock_div_t clk_div;

        offset = RDC_CLOCK_DIV;

        clk_div.value = 0;
        clk_div.bits.count = count;
        HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL,
            " hpi_rxdma_cfg_clock_div_set: add 0x%llx "
            "handle 0x%llx value 0x%llx",
            handle.regp, handle.regh, clk_div.value));

        HXGE_REG_WR64(handle, offset, clk_div.value);

        return (HPI_SUCCESS);
}


hpi_status_t
hpi_rxdma_rdc_rbr_stat_get(hpi_handle_t handle, uint8_t rdc,
    rdc_rbr_qlen_t *rbr_stat)
{
        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    " rxdma_rdc_rbr_stat_get Illegal RDC Number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        RXDMA_REG_READ64(handle, RDC_RBR_QLEN, rdc, &rbr_stat->value);
        return (HPI_SUCCESS);
}


hpi_status_t
hpi_rxdma_rdc_rcr_qlen_get(hpi_handle_t handle, uint8_t rdc,
    uint16_t *rcr_qlen)
{
        rdc_rcr_qlen_t stats;

        if (!RXDMA_CHANNEL_VALID(rdc)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    " rxdma_rdc_rcr_qlen_get Illegal RDC Number %d \n", rdc));
                return (HPI_RXDMA_RDC_INVALID);
        }

        RXDMA_REG_READ64(handle, RDC_RCR_QLEN, rdc, &stats.value);
        *rcr_qlen =  stats.bits.qlen;
        HPI_DEBUG_MSG((handle.function, HPI_RDC_CTL,
            " rxdma_rdc_rcr_qlen_get RDC %d qlen %x qlen %x\n",
            rdc, *rcr_qlen, stats.bits.qlen));
        return (HPI_SUCCESS);
}

hpi_status_t
hpi_rxdma_channel_rbr_empty_clear(hpi_handle_t handle, uint8_t channel)
{
        rdc_stat_t      cs;

        if (!RXDMA_CHANNEL_VALID(channel)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    " hpi_rxdma_channel_rbr_empty_clear", " channel", channel));
                return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
        }

        RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
        cs.bits.rbr_empty = 1;
        RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);

        return (HPI_SUCCESS);
}

/*
 * This function is called to operate on the control and status register.
 */
hpi_status_t
hpi_rxdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
    rdc_stat_t *cs_p)
{
        int             status = HPI_SUCCESS;
        rdc_stat_t      cs;

        if (!RXDMA_CHANNEL_VALID(channel)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_control_status", "channel", channel));
                return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
        }

        switch (op_mode) {
        case OP_GET:
                RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs_p->value);
                break;

        case OP_SET:
                RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs_p->value);
                break;

        case OP_UPDATE:
                RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
                RXDMA_REG_WRITE64(handle, RDC_STAT, channel,
                    cs_p->value | cs.value);
                break;

        default:
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_control_status", "control", op_mode));
                return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel));
        }

        return (status);
}

/*
 * This function is called to operate on the event mask
 * register which is used for generating interrupts.
 */
hpi_status_t
hpi_rxdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
    rdc_int_mask_t *mask_p)
{
        int             status = HPI_SUCCESS;
        rdc_int_mask_t  mask;

        if (!RXDMA_CHANNEL_VALID(channel)) {
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_event_mask", "channel", channel));
                return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
        }

        switch (op_mode) {
        case OP_GET:
                RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask_p->value);
                break;

        case OP_SET:
                RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel, mask_p->value);
                break;

        case OP_UPDATE:
                RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask.value);
                RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel,
                    mask_p->value | mask.value);
                break;

        default:
                HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
                    "hpi_rxdma_event_mask", "eventmask", op_mode));
                return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel));
        }

        return (status);
}