/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <nxge_impl.h>
#include <npi_mac.h>
#include <npi_rxdma.h>
#include <nxge_hio.h>
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
static int nxge_herr2kerr(uint64_t);
#endif
/*
* The following interfaces are controlled by the
* function control registers. Some global registers
* are to be initialized by only byt one of the 2/4 functions.
* Use the test and set register.
*/
/*ARGSUSED*/
{
!= NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
{
/*
* In multi-partitioning, the partition manager
* who owns function zero should set this multi-partition
* control bit.
*/
return (NXGE_ERROR);
}
"<== nxge_set_fzc_multi_part_ctl"));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
{
"<== nxge_set_fzc_multi_part_ctl"));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
/*
* System interrupt registers that are under function zero
* management.
*/
{
/* Configure the initial timer resolution */
return (status);
}
if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/*
* Set up the logical device group's logical devices that
* the group owns.
*/
goto fzc_intr_init_exit;
/* Configure the system interrupt data */
goto fzc_intr_init_exit;
}
return (status);
}
{
int i, j;
return (NXGE_ERROR);
}
return (NXGE_ERROR);
}
"==> nxge_fzc_intr_ldg_num_set "
"<== nxge_f(Neptune): # ldv %d "
ldvp->ldg_assigned);
if (rs != NPI_SUCCESS) {
"<== nxge_fzc_intr_ldg_num_set failed "
" rs 0x%x ldv %d ldg %d",
return (NXGE_ERROR | rs);
}
"<== nxge_fzc_intr_ldg_num_set OK "
" ldv %d ldg %d",
}
}
return (NXGE_OK);
}
{
return (NXGE_ERROR);
}
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
{
int i;
"<== nxge_fzc_intr_sid_set: no ldg"));
return (NXGE_ERROR);
}
"==> nxge_fzc_intr_sid_set(%d): func %d group %d "
"vector %d",
if (rs != NPI_SUCCESS) {
"<== nxge_fzc_intr_sid_set:failed 0x%x",
rs));
return (NXGE_ERROR | rs);
}
}
return (NXGE_OK);
}
/*
* nxge_init_fzc_rdc
*
* Initialize all of a RDC's FZC_DMC registers.
* This is executed by the service domain, on behalf of a
* guest domain, who cannot access these registers.
*
* Arguments:
* nxgep
* channel The channel to initialize.
*
* NPI_NXGE function calls:
* nxge_init_fzc_rdc_pages()
*
* Context:
* Service Domain
*/
/*ARGSUSED*/
{
/*
* Initialize the RxDMA channel-specific FZC control
* registers.
*/
/* Reset RXDMA channel */
if (status != NPI_SUCCESS) {
"==> nxge_init_fzc_rdc: npi_rxdma_cfg_rdc_reset(%d) "
return (NXGE_ERROR | status);
}
/*
* These values have been copied from
* nxge_txdma.c:nxge_map_txdma_channel_cfg_ring().
*/
#if !defined(NIU_HV_WORKAROUND)
#else
"==> nxge_init_fzc_rxdma_channel: N2_NIU - NEED to "
"set up logical pages"));
/* Initialize the RXDMA logical pages */
return (status);
}
#endif
} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/* Initialize the RXDMA logical pages */
return (status);
}
} else {
return (NXGE_ERROR);
}
/*
* Configure RED parameters
*/
"==> nxge_init_fzc_rxdma_channel_red(thre_sync %d(%x))",
return (status);
}
/*
* nxge_init_fzc_rxdma_channel
*
* Initialize all per-channel FZC_DMC registers.
*
* Arguments:
* nxgep
* channel The channel to start
*
* NPI_NXGE function calls:
* nxge_init_hv_fzc_rxdma_channel_pages()
* nxge_init_fzc_rxdma_channel_pages()
* nxge_init_fzc_rxdma_channel_red()
*
* Context:
* Service Domain
*/
/*ARGSUSED*/
{
#ifndef NIU_HV_WORKAROUND
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
"==> nxge_init_fzc_rxdma_channel: N2_NIU - call HV "
"set up logical pages"));
/* Initialize the RXDMA logical pages */
rbr_ring);
return (status);
}
#endif
#else
"==> nxge_init_fzc_rxdma_channel: N2_NIU - NEED to "
"set up logical pages"));
/* Initialize the RXDMA logical pages */
rbr_ring);
return (status);
}
#endif
} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/* Initialize the RXDMA logical pages */
return (status);
}
} else {
return (NXGE_ERROR);
}
/* Configure RED parameters */
return (status);
}
/*
* nxge_init_fzc_rdc_pages
*
* Configure a TDC's logical pages.
*
* This function is executed by the service domain, on behalf of
* a guest domain, to whom this RDC has been loaned.
*
* Arguments:
* nxgep
* channel The channel to initialize.
* page0 Logical page 0 definition.
* page1 Logical page 1 definition.
*
* Notes:
* I think that this function can be called from any
* domain, but I need to check.
*
* hv_niu_tx_logical_page_conf()
* hv_niu_tx_logical_page_info()
*
* Context:
* Any domain
*/
{
"==> nxge_init_fzc_txdma_channel_pages"));
#ifndef NIU_HV_WORKAROUND
"<== nxge_init_fzc_rdc_pages: "
"N2_NIU: no need to set rxdma logical pages"));
return (NXGE_OK);
}
#else
"<== nxge_init_fzc_rdc_pages: "
"N2_NIU: NEED to set rxdma logical pages"));
}
#endif
/*
* Initialize logical page 1.
*/
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Initialize logical page 2.
*/
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Initialize the page handle.
* (In the current driver, this is always set to 0.)
*/
page_handle = 0;
if (rs == NPI_SUCCESS) {
return (NXGE_OK);
} else {
return (NXGE_ERROR | rs);
}
}
/*ARGSUSED*/
{
"==> nxge_init_fzc_rxdma_channel_pages"));
/*
* Initialize logical page 1.
*/
(p_dma_log_page_t)&cfg);
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/*
* Initialize logical page 2.
*/
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/* Initialize the page handle */
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
"<== nxge_init_fzc_rxdma_channel_pages"));
return (NXGE_OK);
}
/*ARGSUSED*/
{
"==> nxge_init_fzc_rxdma_channel_red(thre_sync %d(%x))",
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
"<== nxge_init_fzc_rxdma_channel_red"));
return (NXGE_OK);
}
/*
* nxge_init_fzc_tdc
*
* Initialize all of a TDC's FZC_DMC registers.
* This is executed by the service domain, on behalf of a
* guest domain, who cannot access these registers.
*
* Arguments:
* nxgep
* channel The channel to initialize.
*
* NPI_NXGE function calls:
* nxge_init_fzc_tdc_pages()
* npi_txc_dma_max_burst_set()
*
* Registers accessed:
* TXC_DMA_MAX_BURST
*
* Context:
* Service Domain
*/
/*ARGSUSED*/
{
/*
* These values have been copied from
* nxge_txdma.c:nxge_map_txdma_channel_cfg_ring().
*/
#ifdef NIU_HV_WORKAROUND
"==> nxge_init_fzc_txdma_channel "
"N2_NIU: NEED to set up txdma logical pages"));
/* Initialize the TXDMA logical pages */
}
#endif
if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/* Initialize the TXDMA logical pages */
} else
return (NXGE_ERROR);
}
/*
* Configure the TXC DMA Max Burst value.
*
* PRM.13.5
*
* TXC DMA Max Burst. TXC_DMA_MAX (FZC_TXC + 0000016)
* 19:0 dma_max_burst RW
* Max burst value associated with DMA. Used by DRR engine
* for computing when DMA has gone into deficit.
*/
(void) npi_txc_dma_max_burst_set(
return (status);
}
/*ARGSUSED*/
{
"==> nxge_init_fzc_txdma_channel"));
#ifndef NIU_HV_WORKAROUND
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
"==> nxge_init_fzc_txdma_channel "
"N2_NIU: call HV to set up txdma logical pages"));
return (status);
}
#endif
#else
"==> nxge_init_fzc_txdma_channel "
"N2_NIU: NEED to set up txdma logical pages"));
/* Initialize the TXDMA logical pages */
#endif
} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/* Initialize the TXDMA logical pages */
} else {
return (NXGE_ERROR);
}
/*
* Configure Transmit DRR Weight parameters
* (It actually programs the TXC max burst register).
*/
"<== nxge_init_fzc_txdma_channel"));
return (status);
}
{
int table;
"==> nxge_init_fzc_rx_common null ptr"));
return (NXGE_ERROR);
}
/*
* 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.
*/
if (rs != NPI_SUCCESS)
return (NXGE_ERROR | rs);
#if defined(__i386)
if (rs != NPI_SUCCESS)
return (NXGE_ERROR | rs);
if (rs != NPI_SUCCESS)
return (NXGE_ERROR | rs);
#endif
/*
* Enable WRED and program an initial value.
* Use time to set the initial random number.
*/
if (rs != NPI_SUCCESS)
return (NXGE_ERROR | rs);
/* Does this table belong to <nxgep>? */
}
}
/* Ethernet Timeout Counter (?) */
"<== nxge_init_fzc_rx_common:status 0x%08x", status));
return (status);
}
{
/* This RDC table must have been previously bound to <nxge>. */
"nxge_init_fzc_rdc_tbl(%d): not owner", table));
return (NXGE_ERROR);
} else {
}
if (rs != NPI_SUCCESS) {
}
return (status);
}
static
int
{
int i;
/* is the caller asking for a particular table? */
"<== nxge_fzc_rdc_tbl_bind(%d)", rdc_tbl));
return (rdc_tbl);
}
} else { /* The caller will take any old RDC table. */
for (i = 0; i < NXGE_MAX_RDC_GROUPS; i++) {
/* It is now bound. */
"<== nxge_fzc_rdc_tbl_bind: %d", i));
return (i);
}
}
}
return (-EBUSY); /* RDC tables are bound. */
}
int
int grp_index,
int acceptNoSubstitutes)
{
int index;
if (acceptNoSubstitutes)
return (index);
if (index < 0) {
"nxge_fzc_rdc_tbl_init: "
"there are no free RDC tables!"));
return (index);
}
}
return (index);
}
int
{
return (0);
rdc_tbl));
"nxge_fzc_rdc_tbl_unbind(%d): func%d not owner",
return (EINVAL);
} else {
}
rdc_tbl));
return (0);
}
{
int i;
/*
* Initialize the port scheduler DRR weight.
* npi_rxdma_cfg_port_ddr_weight();
*/
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
}
/* Program the default RDC of a port */
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/*
* Configure the MAC host info table with RDC tables
*/
}
if (rs != NPI_SUCCESS)
return (NXGE_ERROR | rs);
}
"<== nxge_init_fzc_rxdma_port rs 0x%08x", rs));
return (NXGE_OK);
}
{
if (rs & NPI_FAILURE)
return (NXGE_ERROR | rs);
return (NXGE_OK);
}
/*
* nxge_init_fzc_tdc_pages
*
* Configure a TDC's logical pages.
*
* This function is executed by the service domain, on behalf of
* a guest domain, to whom this TDC has been loaned.
*
* Arguments:
* nxgep
* channel The channel to initialize.
* page0 Logical page 0 definition.
* page1 Logical page 1 definition.
*
* Notes:
* I think that this function can be called from any
* domain, but I need to check.
*
* hv_niu_tx_logical_page_conf()
* hv_niu_tx_logical_page_info()
*
* Context:
* Any domain
*/
{
"==> nxge_init_fzc_txdma_channel_pages"));
#ifndef NIU_HV_WORKAROUND
"<== nxge_init_fzc_tdc_pages: "
"N2_NIU: no need to set txdma logical pages"));
return (NXGE_OK);
}
#else
"<== nxge_init_fzc_tdc_pages: "
"N2_NIU: NEED to set txdma logical pages"));
}
#endif
/*
* Initialize logical page 1.
*/
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Initialize logical page 2.
*/
!= NPI_SUCCESS)
return (NXGE_ERROR | rs);
/*
* Initialize the page handle.
* (In the current driver, this is always set to 0.)
*/
page_handle.value = 0;
if (rs == NPI_SUCCESS) {
return (NXGE_OK);
} else {
return (NXGE_ERROR | rs);
}
}
{
"==> nxge_init_fzc_txdma_channel_pages"));
#ifndef NIU_HV_WORKAROUND
"<== nxge_init_fzc_txdma_channel_pages: "
"N2_NIU: no need to set txdma logical pages"));
return (NXGE_OK);
}
#else
"<== nxge_init_fzc_txdma_channel_pages: "
"N2_NIU: NEED to set txdma logical pages"));
}
#endif
/*
* Initialize logical page 1.
*/
(p_dma_log_page_t)&cfg);
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/*
* Initialize logical page 2.
*/
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/* Initialize the page handle */
if (rs == NPI_SUCCESS) {
return (NXGE_OK);
} else {
return (NXGE_ERROR | rs);
}
}
{
if (rs == NPI_SUCCESS) {
return (NXGE_OK);
} else {
return (NXGE_ERROR | rs);
}
}
{
if (rs == NPI_SUCCESS) {
return (NXGE_OK);
} else {
return (NXGE_ERROR | rs);
}
}
/*
* nxge_init_hv_fzc_txdma_channel_pages
*
* Configure a TDC's logical pages.
*
* Arguments:
* nxgep
* channel The channel to initialize.
* tx_ring_p The transmit ring.
*
* Notes:
* I think that this function can be called from any
* domain, but I need to check.
*
* hv_niu_tx_logical_page_conf()
* hv_niu_tx_logical_page_info()
*
* Context:
* Any domain
*/
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
{
int err;
#ifdef DEBUG
#endif
"==> nxge_init_hv_fzc_txdma_channel_pages"));
return (NXGE_OK);
}
/*
* Initialize logical page 1 for data buffers.
*/
(uint64_t)0, N2NIU_TX_LP_CONF,
if (err != 0) {
"<== nxge_init_hv_fzc_txdma_channel_pages: channel %d "
"error status 0x%x "
"(page 0 data buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
err,
return (NXGE_ERROR | err);
}
#ifdef DEBUG
(uint64_t)0, N2NIU_TX_LP_INFO,
"==> nxge_init_hv_fzc_txdma_channel_pages: channel %d "
"ok status 0x%x "
"(page 0 data buf) hverr 0x%llx "
"set ioaddr_pp $%p "
"set size 0x%llx "
"get ra ioaddr_pp $%p "
"get size 0x%llx ",
err,
ra,
size));
#endif
"==> nxge_init_hv_fzc_txdma_channel_pages: channel %d "
"(page 0 data buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
/*
* Initialize logical page 2 for control buffers.
*/
"==> nxge_init_hv_fzc_txdma_channel_pages: channel %d"
"ok status 0x%x "
"(page 1 cntl buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
err,
if (err != 0) {
"<== nxge_init_hv_fzc_txdma_channel_pages: channel %d"
"error status 0x%x "
"(page 1 cntl buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
err,
return (NXGE_ERROR | err);
}
#ifdef DEBUG
"==> nxge_init_hv_fzc_txdma_channel_pages: channel %d "
"(page 1 cntl buf) hverr 0x%llx "
"set ioaddr_pp $%p "
"set size 0x%llx "
"get ra ioaddr_pp $%p "
"get size 0x%llx ",
ra,
size));
#endif
"<== nxge_init_hv_fzc_txdma_channel_pages"));
return (NXGE_OK);
}
/*ARGSUSED*/
{
int err;
#ifdef DEBUG
#endif
"==> nxge_init_hv_fzc_rxdma_channel_pages"));
return (NXGE_OK);
}
/* Initialize data buffers for page 0 */
(uint64_t)0, N2NIU_RX_LP_CONF,
if (err != 0) {
"<== nxge_init_hv_fzc_rxdma_channel_pages: channel %d"
"error status 0x%x "
"(page 0 data buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
err,
return (NXGE_ERROR | err);
}
#ifdef DEBUG
(uint64_t)0, N2NIU_RX_LP_INFO,
"==> nxge_init_hv_fzc_rxdma_channel_pages: channel %d "
"ok status 0x%x "
"(page 0 data buf) hverr 0x%llx "
"set databuf ioaddr_pp $%p "
"set databuf size 0x%llx "
"get databuf ra ioaddr_pp %p "
"get databuf size 0x%llx",
err,
ra,
size));
#endif
/* Initialize control buffers for logical page 1. */
if (err != 0) {
"<== nxge_init_hv_fzc_rxdma_channel_pages: channel %d"
"error status 0x%x "
"(page 1 cntl buf) hverr 0x%llx "
"ioaddr_pp $%p "
"size 0x%llx ",
err,
return (NXGE_ERROR | err);
}
#ifdef DEBUG
"==> nxge_init_hv_fzc_rxdma_channel_pages: channel %d "
"error status 0x%x "
"(page 1 cntl buf) hverr 0x%llx "
"set cntl ioaddr_pp $%p "
"set cntl size 0x%llx "
"get cntl ioaddr_pp $%p "
"get cntl size 0x%llx ",
err,
ra,
size));
#endif
"<== nxge_init_hv_fzc_rxdma_channel_pages"));
return (NXGE_OK);
}
/*
* Map hypervisor error code to errno. Only
* H_ENORADDR, H_EBADALIGN and H_EINVAL are meaningful
* for niu driver. Any other error codes are mapped to EINVAL.
*/
static int
{
int s_errcode;
switch (hv_errcode) {
case H_ENORADDR:
case H_EBADALIGN:
break;
case H_EOK:
s_errcode = 0;
break;
default:
break;
}
return (s_errcode);
}
{
"==> nxge_init_hv_fzc_lp_op"));
"==> nxge_init_hv_fzc_lp_op (major %d): channel %d op_type 0x%x "
"page_no %d ioaddr_pp $%p ioaddr_size 0x%llx",
/* Call the transmit conf function. */
switch (major) {
case NIU_MAJOR_VER: /* 1 */
switch (op_type) {
case N2NIU_TX_LP_CONF:
"==> nxge_init_hv_fzc_lp_op(tx_conf): major %d "
break;
case N2NIU_TX_LP_INFO:
(uint64_t *)ioaddr_size);
break;
case N2NIU_RX_LP_CONF:
break;
case N2NIU_RX_LP_INFO:
(uint64_t *)ioaddr_size);
"==> nxge_init_hv_fzc_lp_op(rx_conf): major %d "
break;
default:
"==> nxge_init_hv_fzc_lp_op(rx_conf): major %d "
"invalid op 0x%x hverr 0x%x", major,
break;
}
break;
case NIU_MAJOR_VER_2: /* 2 */
switch (op_type) {
case N2NIU_TX_LP_CONF:
"==> nxge_init_hv_fzc_lp_op(tx_conf): major %d "
break;
case N2NIU_TX_LP_INFO:
(uint64_t *)ioaddr_size);
break;
case N2NIU_RX_LP_CONF:
"==> nxge_init_hv_fzc_lp_op(rx_conf): major %d "
break;
case N2NIU_RX_LP_INFO:
(uint64_t *)ioaddr_size);
break;
default:
"==> nxge_init_hv_fzc_lp_op(rx_conf): major %d "
"invalid op 0x%x hverr 0x%x", major,
break;
}
break;
default:
"==> nxge_init_hv_fzc_lp_op(rx_conf): invalid major %d "
break;
}
"<== nxge_init_hv_fzc_lp_op: 0x%x", hverr));
return (hverr);
}
#endif /* sun4v and NIU_LP_WORKAROUND */