/*
 * 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	<hxge_impl.h>
#include	<hpi_vmac.h>
#include	<hpi_rxdma.h>

/*
 * System interrupt registers that are under function zero management.
 */
hxge_status_t
hxge_fzc_intr_init(p_hxge_t hxgep)
{
	hxge_status_t	status = HXGE_OK;

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_fzc_intr_init"));

	/* Configure the initial timer resolution */
	if ((status = hxge_fzc_intr_tmres_set(hxgep)) != HXGE_OK) {
		return (status);
	}

	/*
	 * Set up the logical device group's logical devices that
	 * the group owns.
	 */
	if ((status = hxge_fzc_intr_ldg_num_set(hxgep)) != HXGE_OK) {
		return (status);
	}

	/* Configure the system interrupt data */
	if ((status = hxge_fzc_intr_sid_set(hxgep)) != HXGE_OK) {
		return (status);
	}

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_init"));

	return (status);
}

hxge_status_t
hxge_fzc_intr_ldg_num_set(p_hxge_t hxgep)
{
	p_hxge_ldg_t	ldgp;
	p_hxge_ldv_t	ldvp;
	hpi_handle_t	handle;
	int		i, j;
	hpi_status_t	rs = HPI_SUCCESS;

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_fzc_intr_ldg_num_set"));

	if (hxgep->ldgvp == NULL) {
		return (HXGE_ERROR);
	}

	ldgp = hxgep->ldgvp->ldgp;
	ldvp = hxgep->ldgvp->ldvp;
	if (ldgp == NULL || ldvp == NULL) {
		return (HXGE_ERROR);
	}

	handle = HXGE_DEV_HPI_HANDLE(hxgep);

	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_fzc_intr_ldg_num_set "
		    "<== hxge_f(Hydra): # ldv %d in group %d", ldgp->nldvs,
		    ldgp->ldg));

		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
			rs = hpi_fzc_ldg_num_set(handle, ldvp->ldv,
			    ldvp->ldg_assigned);
			if (rs != HPI_SUCCESS) {
				HXGE_DEBUG_MSG((hxgep, INT_CTL,
				    "<== hxge_fzc_intr_ldg_num_set failed "
				    " rs 0x%x ldv %d ldg %d",
				    rs, ldvp->ldv, ldvp->ldg_assigned));
				return (HXGE_ERROR | rs);
			}
			HXGE_DEBUG_MSG((hxgep, INT_CTL,
			    "<== hxge_fzc_intr_ldg_num_set OK ldv %d ldg %d",
			    ldvp->ldv, ldvp->ldg_assigned));
		}
	}

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_ldg_num_set"));
	return (HXGE_OK);
}

hxge_status_t
hxge_fzc_intr_tmres_set(p_hxge_t hxgep)
{
	hpi_handle_t	handle;
	hpi_status_t	rs = HPI_SUCCESS;

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_fzc_intr_tmrese_set"));
	if (hxgep->ldgvp == NULL) {
		return (HXGE_ERROR);
	}

	handle = HXGE_DEV_HPI_HANDLE(hxgep);
	if ((rs = hpi_fzc_ldg_timer_res_set(handle, hxgep->ldgvp->tmres))) {
		return (HXGE_ERROR | rs);
	}

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_tmrese_set"));
	return (HXGE_OK);
}

hxge_status_t
hxge_fzc_intr_sid_set(p_hxge_t hxgep)
{
	hpi_handle_t	handle;
	p_hxge_ldg_t	ldgp;
	fzc_sid_t	sid;
	int		i;
	hpi_status_t	rs = HPI_SUCCESS;

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_fzc_intr_sid_set"));
	if (hxgep->ldgvp == NULL) {
		HXGE_DEBUG_MSG((hxgep, INT_CTL,
		    "<== hxge_fzc_intr_sid_set: no ldg"));
		return (HXGE_ERROR);
	}

	handle = HXGE_DEV_HPI_HANDLE(hxgep);
	ldgp = hxgep->ldgvp->ldgp;
	HXGE_DEBUG_MSG((hxgep, INT_CTL,
	    "==> hxge_fzc_intr_sid_set: #int %d", hxgep->ldgvp->ldg_intrs));
	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
		sid.ldg = ldgp->ldg;
		sid.vector = ldgp->vector;
		HXGE_DEBUG_MSG((hxgep, INT_CTL,
		    "==> hxge_fzc_intr_sid_set(%d): group %d vector %d",
		    i, sid.ldg, sid.vector));
		rs = hpi_fzc_sid_set(handle, sid);
		if (rs != HPI_SUCCESS) {
			HXGE_DEBUG_MSG((hxgep, INT_CTL,
			    "<== hxge_fzc_intr_sid_set:failed 0x%x", rs));
			return (HXGE_ERROR | rs);
		}
	}

	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_sid_set"));
	return (HXGE_OK);
}

/*
 * Receive DMA registers that are under function zero management.
 */
/*ARGSUSED*/
hxge_status_t
hxge_init_fzc_rxdma_channel(p_hxge_t hxgep, uint16_t channel,
	p_rx_rbr_ring_t rbr_p, p_rx_rcr_ring_t rcr_p, p_rx_mbox_t mbox_p)
{
	hxge_status_t status = HXGE_OK;

	HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_init_fzc_rxdma_channel"));

	/* Initialize the RXDMA logical pages */
	status = hxge_init_fzc_rxdma_channel_pages(hxgep, channel, rbr_p);
	if (status != HXGE_OK)
		return (status);

	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_init_fzc_rxdma_channel"));
	return (status);
}

/*ARGSUSED*/
hxge_status_t
hxge_init_fzc_rxdma_channel_pages(p_hxge_t hxgep,
	uint16_t channel, p_rx_rbr_ring_t rbrp)
{
	hpi_handle_t handle;
	hpi_status_t rs = HPI_SUCCESS;

	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
	    "==> hxge_init_fzc_rxdma_channel_pages"));

	handle = HXGE_DEV_HPI_HANDLE(hxgep);

	/* Initialize the page handle */
	rs = hpi_rxdma_cfg_logical_page_handle(handle, channel,
	    rbrp->page_hdl.bits.handle);
	if (rs != HPI_SUCCESS)
		return (HXGE_ERROR | rs);

	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
	    "<== hxge_init_fzc_rxdma_channel_pages"));
	return (HXGE_OK);
}

/*ARGSUSED*/
hxge_status_t
hxge_init_fzc_txdma_channel(p_hxge_t hxgep, uint16_t channel,
	p_tx_ring_t tx_ring_p, p_tx_mbox_t mbox_p)
{
	hxge_status_t status = HXGE_OK;

	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_init_fzc_txdma_channel"));

	/* Initialize the TXDMA logical pages */
	(void) hxge_init_fzc_txdma_channel_pages(hxgep, channel, tx_ring_p);

	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_init_fzc_txdma_channel"));
	return (status);
}

hxge_status_t
hxge_init_fzc_rx_common(p_hxge_t hxgep)
{
	hpi_handle_t	handle;
	hpi_status_t	rs = HPI_SUCCESS;
	hxge_status_t	status = HXGE_OK;

	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_init_fzc_rx_common"));
	handle = HXGE_DEV_HPI_HANDLE(hxgep);

	/*
	 * Configure the rxdma clock divider
	 * This is the granularity counter based on
	 * the hardware system clock (i.e. 300 Mhz) and
	 * it is running around 3 nanoseconds.
	 * So, set the clock divider counter to 1000 to get
	 * microsecond granularity.
	 * For example, for a 3 microsecond timeout, the timeout
	 * will be set to 1.
	 */
	rs = hpi_rxdma_cfg_clock_div_set(handle, RXDMA_CK_DIV_DEFAULT);
	if (rs != HPI_SUCCESS)
		return (HXGE_ERROR | rs);

	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
	    "<== hxge_init_fzc_rx_common:status 0x%08x", status));
	return (status);
}

hxge_status_t
hxge_init_fzc_txdma_channel_pages(p_hxge_t hxgep, uint16_t channel,
	p_tx_ring_t tx_ring_p)
{
	hpi_handle_t		handle;
	hpi_status_t		rs = HPI_SUCCESS;

	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
	    "==> hxge_init_fzc_txdma_channel_pages"));

	handle = HXGE_DEV_HPI_HANDLE(hxgep);

	/* Initialize the page handle */
	rs = hpi_txdma_log_page_handle_set(handle, channel,
	    &tx_ring_p->page_hdl);

	if (rs == HPI_SUCCESS)
		return (HXGE_OK);
	else
		return (HXGE_ERROR | rs);
}

hxge_status_t
hxge_fzc_sys_err_mask_set(p_hxge_t hxgep, boolean_t mask)
{
	hpi_status_t	rs = HPI_SUCCESS;
	hpi_handle_t	handle;

	handle = HXGE_DEV_HPI_HANDLE(hxgep);
	rs = hpi_fzc_sys_err_mask_set(handle, mask);
	if (rs == HPI_SUCCESS)
		return (HXGE_OK);
	else
		return (HXGE_ERROR | rs);
}