/*
 * 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.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <hpi_vir.h>
#include <hxge_defs.h>
#include <hxge_impl.h>

/*
 * Set up a logical group number that a logical device belongs to.
 */
hpi_status_t
hpi_fzc_ldg_num_set(hpi_handle_t handle, uint8_t ld, uint8_t ldg)
{
	ld_grp_ctrl_t	gnum;

	if (!LD_VALID(ld)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_fzc_ldg_num_set ld <0x%x>", ld));
		return (HPI_FAILURE | HPI_VIR_LD_INVALID(ld));
	}

	if (!LDG_VALID(ldg)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_fzc_ldg_num_set ldg <0x%x>", ldg));
		return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ld));
	}

	gnum.value = 0;
	gnum.bits.num = ldg;

	HXGE_REG_WR32(handle, LD_GRP_CTRL + LD_NUM_OFFSET(ld), gnum.value);

	return (HPI_SUCCESS);
}

/*
 * Get device state vectors.
 */
hpi_status_t
hpi_ldsv_ldfs_get(hpi_handle_t handle, uint8_t ldg, uint32_t *vector0_p,
    uint32_t *vector1_p)
{
	int	status;

	if ((status = hpi_ldsv_get(handle, ldg, VECTOR0, vector0_p))) {
		return (status);
	}
	if ((status = hpi_ldsv_get(handle, ldg, VECTOR1, vector1_p))) {
		return (status);
	}

	return (HPI_SUCCESS);
}

/*
 * Get device state vectors.
 */
hpi_status_t
hpi_ldsv_get(hpi_handle_t handle, uint8_t ldg, ldsv_type_t vector,
    uint32_t *ldf_p)
{
	uint32_t	offset;

	if (!LDG_VALID(ldg)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_ldsv_get Invalid Input ldg <0x%x>", ldg));
		return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ldg));
	}

	switch (vector) {
	case VECTOR0:
		offset = LDSV0 + LDSV_OFFSET(ldg);
		break;

	case VECTOR1:
		offset = LDSV1 + LDSV_OFFSET(ldg);
		break;

	default:
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_ldsv_get Invalid Input: ldsv type <0x%x>", vector));
		return (HPI_FAILURE | HPI_VIR_LDSV_INVALID(vector));
	}

	HXGE_REG_RD32(handle, offset, ldf_p);

	return (HPI_SUCCESS);
}

/*
 * Set the mask bits for both ldf0 and ldf1.
 */
hpi_status_t
hpi_intr_mask_set(hpi_handle_t handle, uint8_t ld, uint8_t ldf_mask)
{
	uint32_t	offset;

	if (!LD_VALID(ld)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_intr_mask_set ld", ld));
		return (HPI_FAILURE | HPI_VIR_LD_INVALID(ld));
	}

	ldf_mask &= LD_IM_MASK;
	offset = LDSV_OFFSET_MASK(ld);

	HPI_DEBUG_MSG((handle.function, HPI_VIR_CTL,
	    "hpi_intr_mask_set: ld %d offset 0x%0x mask 0x%x",
	    ld, offset, ldf_mask));

	HXGE_REG_WR32(handle, offset, (uint32_t)ldf_mask);

	return (HPI_SUCCESS);
}

/*
 * Set interrupt timer and arm bit.
 */
hpi_status_t
hpi_intr_ldg_mgmt_set(hpi_handle_t handle, uint8_t ldg, boolean_t arm,
    uint8_t timer)
{
	ld_intr_mgmt_t	mgm;

	if (!LDG_VALID(ldg)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_intr_ldg_mgmt_set Invalid Input: ldg <0x%x>", ldg));
		return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ldg));
	}

	if (!LD_INTTIMER_VALID(timer)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_intr_ldg_mgmt_set Invalid Input"
		    " timer <0x%x>", timer));
		return (HPI_FAILURE | HPI_VIR_INTM_TM_INVALID(ldg));
	}

	if (arm) {
		mgm.bits.arm = 1;
	} else {
		HXGE_REG_RD32(handle, LD_INTR_MGMT + LDSV_OFFSET(ldg),
		    &mgm.value);
	}

	mgm.bits.timer = timer;
	HXGE_REG_WR32(handle, LD_INTR_MGMT + LDSV_OFFSET(ldg), mgm.value);

	HPI_DEBUG_MSG((handle.function, HPI_VIR_CTL,
	    " hpi_intr_ldg_mgmt_set: ldg %d reg offset 0x%x",
	    ldg, LD_INTR_MGMT + LDSV_OFFSET(ldg)));

	return (HPI_SUCCESS);
}

/*
 * Set the timer resolution.
 */
hpi_status_t
hpi_fzc_ldg_timer_res_set(hpi_handle_t handle, uint32_t res)
{
	ld_intr_tim_res_t	tm;

	if (res > LDGTITMRES_RES_MASK) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_fzc_ldg_timer_res_set Invalid Input: res <0x%x>",
		    res));
		return (HPI_FAILURE | HPI_VIR_TM_RES_INVALID);
	}

	tm.value = 0;
	tm.bits.res = res;

	HXGE_REG_WR32(handle, LD_INTR_TIM_RES, tm.value);

	return (HPI_SUCCESS);
}

/*
 * Set the system interrupt data.
 */
hpi_status_t
hpi_fzc_sid_set(hpi_handle_t handle, fzc_sid_t sid)
{
	sid_t	sd;

	if (!LDG_VALID(sid.ldg)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_fzc_sid_set Invalid Input: ldg <0x%x>", sid.ldg));
		return (HPI_FAILURE | HPI_VIR_LDG_INVALID(sid.ldg));
	}

	if (!SID_VECTOR_VALID(sid.vector)) {
		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
		    " hpi_fzc_sid_set Invalid Input: vector <0x%x>",
		    sid.vector));

		return (HPI_FAILURE | HPI_VIR_SID_VEC_INVALID(sid.vector));
	}

	sd.value = 0;
	sd.bits.data = sid.vector;
	HXGE_REG_WR32(handle,  SID + LDG_SID_OFFSET(sid.ldg), sd.value);

	return (HPI_SUCCESS);
}

/*
 * Mask/Unmask the device error mask bits.
 */
hpi_status_t
hpi_fzc_sys_err_mask_set(hpi_handle_t handle, boolean_t mask)
{
	dev_err_mask_t	dev_mask;

	dev_mask.value = 0;
	if (mask) {
		dev_mask.bits.tdc_mask0 = 1;
		dev_mask.bits.rdc_mask0 = 1;
		dev_mask.bits.vnm_pio_mask1 = 1;
		dev_mask.bits.tdc_mask1 = 1;
		dev_mask.bits.rdc_mask1 = 1;
		dev_mask.bits.peu_mask1 = 1;
	}

	HXGE_REG_WR32(handle, DEV_ERR_MASK, dev_mask.value);
	return (HPI_SUCCESS);
}

/*
 * Get the system error stats.
 */
hpi_status_t
hpi_fzc_sys_err_stat_get(hpi_handle_t handle, dev_err_stat_t *statp)
{
	HXGE_REG_RD32(handle,  DEV_ERR_STAT, &statp->value);
	return (HPI_SUCCESS);
}