/*
* 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 2014 QLogic Corporation
* The contents of this file are subject to the terms of the
* QLogic End User License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
*/
#include "bnxe.h"
/*
* The interrupt status bit vector is as follows:
*
* bit 0: default interrupt
*
* Single Mode:
*
* bits 1-16: Function 1 (RSS 0-15)
*
* Multi-Function Mode:
*
* bits 1-4: Virtual Function 1 (RSS 0-3)
* bits 5-8: Virtual Function 2 (RSS 4-7)
* bits 9-12: Virtual Function 3 (RSS 8-11)
* bits 13-16: Virtual Function 4 (RSS 12-15)
*
* While processing interrupts the programmatic index used for the default
* status block is 16 and the RSS status blocks are shifted down one (i.e.
* 0-15).
*
* Solaris defaults to 2 MSIX interrupts per function so only the default
* interrupt plus one RSS interrupt is used. This default behavior can be
*/
{
"UNKNOWN";
}
{
/* find the RSS status blocks */
{
{
}
else
{
}
while (pTmp)
{
{
break;
}
}
{
}
}
/* find the default status block */
while (pTmp)
{
{
break;
}
}
{
}
}
{
if (fromISR)
{
/*
* If in an ISR and poll mode is ON then poll mode was flipped in the
* ISR which can occur during Rx processing. If this is the case then
* don't do anything. Only re-enable the IGU when poll mode is OFF.
*/
if (!pRxQ->inPollMode)
{
}
}
else
{
if (!pRxQ->inPollMode)
{
/* Why are intrs getting enabled on the ring twice...? */
"%s: Ring %d, enable intrs and NOT in poll mode!",
}
pRxQ->intrEnableCnt++;
}
}
{
if (fromISR)
{
/* we should never get here when in poll mode... */
}
else
{
if (pRxQ->inPollMode)
{
/* Why are intrs getting disabled on the ring twice...? */
"%s: Ring %d, disable intrs and ALREADY in poll mode!",
}
/*
* Note here that the interrupt can already be disabled if GLDv3
* is disabling the interrupt under the context of an ISR. This is
* OK as the inPollMode flag will tell the ISR not to re-enable the
* interrupt upon return.
*/
pRxQ->intrDisableCnt++;
}
}
{
0, 0, DDI_DMA_SYNC_FORKERNEL);
if (pUM->fmCapabilities &&
{
}
if (lm_is_def_sb_updated(pLM) == 0)
{
if (pUM->fmCapabilities &&
{
}
return;
}
/* get a local copy of the indices from the status block */
if (activity_flg & LM_DEF_ATTN_ACTIVE)
{
/* Attentions! Usually these are bad things we don't want to see */
// NOTE: in case the status index of the attention has changed
// already (while processing), we could override with it our local
// copy. However, this is not a must, since it will be caught at the
// end of the loop with the call to lm_is_sb_updated(). In case the
// dpc_loop_cnt has exhausted, no worry, since will get an interrupt
// for that at a later time.
// find out which lines are asserted/deasserted with account to
// their states, ASSERT if necessary.
if (asserted_proc_grps)
{
if (pUM->fmCapabilities &&
{
}
}
// keep in mind that in the same round, it is possible that this
// func will have processing to do regarding deassertion on bits
// that are different than the ones processed earlier for assertion
// processing.
if (deasserted_proc_grps)
{
if (pUM->fmCapabilities &&
{
}
}
}
if (activity_flg & LM_DEF_USTORM_ACTIVE)
{
{
}
{
}
}
if (activity_flg & LM_DEF_CSTORM_ACTIVE)
{
if (lm_is_eq_completion(pLM))
{
}
{
/* XXX Possible? */
}
{
/* XXX iSCSI Tx. NO! */
}
{
}
}
}
/*
* This is the polling path for an individual Rx Ring. Here we simply pull
* any pending packets out of the hardware and put them into the wait queue.
* Note that there might already be packets in the wait queue which is OK as
* the caller will call BnxeRxRingProcess() next to process the queue.
*/
{
idx, drv_rss_id);
/* use drv_rss_id for mapping into status block array (from LM) */
0, 0, DDI_DMA_SYNC_FORKERNEL);
if (pUM->fmCapabilities &&
{
}
{
return;
}
/* get a local copy of the indices from the status block */
{
/* Rx Completions */
{
}
}
{
/* Tx completions */
{
}
/* XXX Check for L4 Tx and L5 EQ completions. NO! */
}
}
/*
* This is the polling path for the FCoE Ring. Here we don't pull any
* pending packets out of the hardware. We only care about FCoE Fast Path
* completions. FCoE slow path L2 packets are processed via the default
* status block not the LM_NON_RSS_SB. In this path we're assuming that
* the FCoE driver is performing a crashdump.
*/
{
sb_id, drv_rss_id);
/* use sb_id for mapping into status block array (from LM) */
0, 0, DDI_DMA_SYNC_FORKERNEL);
if (pUM->fmCapabilities &&
{
}
{
return;
}
/* get a local copy of the indices from the status block */
{
{
}
}
}
{
sb_id, drv_rss_id);
/* use sb_id for mapping into status block array (from LM) */
0, 0, DDI_DMA_SYNC_FORKERNEL);
if (pUM->fmCapabilities &&
{
}
{
return;
}
/*
* get a local copy of the indices from the status block
* XXX note that here drv_rss_id is assigned to the sb_id
*/
{
/* Rx Completions */
{
}
{
}
/* XXX Check for ISCSI-OOO and L4 TOE Rx completions. NO! */
}
{
/* Tx completions */
{
}
/* XXX Check for L4 Tx and L5 EQ completions. NO! */
/* L4 Tx completions */
{
}
/* L5 EQ completions */
{
//lm_sc_service_eq_intr(pLM, drv_rss_id);
}
}
}
{
if (!pUM->intrEnabled)
{
return DDI_INTR_UNCLAIMED;
}
{
if (pUM->fmCapabilities &&
{
}
if (intrStatus == 0)
{
return DDI_INTR_UNCLAIMED;
}
}
else
{
return DDI_INTR_CLAIMED;
}
while (intrStatus)
{
if (intrStatus & 0x1)
{
if (rss_id == 0)
{
/*
* Default sb only handles FCoE only right now. If this changes
* BnxeServiceDefSbIntr will have to change to return which CIDs
* have packets pending.
*/
}
else
{
/*
* (rss_id - 1) is used because the non-default sbs are located
* in lm_device at indices 0-15.
*/
}
}
intrStatus >>= 1;
rss_id++;
}
return DDI_INTR_CLAIMED;
}
{
if (!pUM->intrEnabled)
{
return DDI_INTR_UNCLAIMED;
}
{
return DDI_INTR_CLAIMED;
}
if (sb_id == DEF_STATUS_BLOCK_IGU_INDEX)
{
/*
* Default sb only handles FCoE only right now. If this changes
* BnxeServiceDefSbIntr will have to change to return which CIDs
* have packets pending.
*/
}
else
{
/*
* Note that polling is not allowed by GLDv3 on the LM_NON_RSS_SB when
* overlapped with FCoE. This is enforced by the BnxeRxRingIntrEnable
* and BnxeRxRingIntrDisable routines. The FCoE driver IS ALLOWED to
* the FCoE driver is performing a crashdump in this case.
*/
{
/* Shouldn't be here! */
}
/* accounts for poll mode */
/* accounts for poll mode */
}
return DDI_INTR_CLAIMED;
}
{
int nintrs = 0;
{
-1 : nintrs;
}
return -1;
}
int intrInum,
int intrCnt,
{
int intrRequest;
int intrActual;
int rc, i;
{
return B_FALSE;
}
intrActual = 0;
/*
* We need to allocate an interrupt block array of maximum size which is
* MAX_RSS_CHAINS plus one for the default interrupt. Even though we
* won't allocate all of those handlers the "inum" value passed to
* ddi_intr_alloc() determines the starting index where the handlers
* will be allocated. See the multi-function block offset documentation
* at the top of this file.
*/
if ((pBlock->pIntrHandleBlockAlloc =
{
intrInum);
return B_FALSE;
}
{
return B_FALSE;
}
/*
* Point 'pIntrHandleBlock' to the starting interrupt index in the
* allocated interrupt block array. This is done so we can easily enable,
* disable, free, etc the interrupts. For 10u8 and beyond the inum value
* is also used as an index into the interrupt block so we point
* pIntrHandleBlock to the inum'th index. For 10u7 and below all
* interrupt allocations start at index 0 per block.
*/
#if 0
#ifdef DDI_INTR_IRM
#else
&pBlock->pIntrHandleBlockAlloc[0];
#endif
#else
if (pBlock->pIntrHandleBlockAlloc[0])
{
&pBlock->pIntrHandleBlockAlloc[0];
}
else
{
}
#endif
if (intrRequest != intrActual)
{
#if 0
for (i = 0; i < intrActual; i++)
{
}
return B_FALSE;
#else
if (intrActual == 0)
{
return B_FALSE;
}
#endif
}
{
goto BnxeIntrBlockAlloc_fail;
}
{
goto BnxeIntrBlockAlloc_fail;
}
{
goto BnxeIntrBlockAlloc_fail;
}
return B_TRUE;
for (i = 0; i < intrActual; i++)
{
}
return B_FALSE;
}
{
int i;
{
return;
}
{
}
}
{
int rc, i, j;
{
case DDI_INTR_TYPE_MSIX:
if ((rc = ddi_intr_add_handler(
{
return B_FALSE;
}
{
if ((rc = ddi_intr_add_handler(
{
for (j = 0; j < i; j++) /* unwind */
{
}
return B_FALSE;
}
}
/*
* fcoeIntr.intrCount == 1 implies LM_NON_RSS_SB (last) status block
* was allocated for FCoE and there was no overlap with the RSS
* allocation.
*/
{
if ((rc = ddi_intr_add_handler(
{
{
}
return B_FALSE;
}
}
break;
case DDI_INTR_TYPE_FIXED:
if ((rc = ddi_intr_add_handler(
{
return B_FALSE;
}
break;
default:
return B_FALSE;
}
return B_TRUE;
}
{
int i;
(void)pUM;
{
return;
}
{
}
}
{
int rc, i, j;
{
return B_TRUE;
}
{
{
return B_FALSE;
}
}
else
{
{
{
for (j = 0; j < i; j++) /* unwind */
{
}
return B_FALSE;
}
}
}
return B_TRUE;
}
{
int i;
{
return;
}
{
}
else
{
{
}
}
}
{
int rc, i, j;
for (i = 0; i < (MAX_RSS_CHAINS + 1); i++)
{
pUM->intrSbNoChangeCnt[i] = 0;
}
/* get the DMA handles for quick access to the status blocks for sync */
/* Enable the default interrupt... */
{
return -1;
}
/* Enable the FCoE interrupt... */
{
return -1;
}
/* Enable the RSS interrupts... */
{
return -1;
}
/* allow the hardware to generate interrupts */
if (pUM->fmCapabilities &&
{
}
/* XXX do not remove this... edavis */
return 0;
}
{
int rc, i;
/* stop the device from generating any interrupts */
if (pUM->fmCapabilities &&
{
}
/*
* Ensure the ISR no longer touches the hardware by making sure the ISR
* is not running or the current run completes. Since interrupts were
* disabled before here and intrEnabled is FALSE, we can be sure
* interrupts will no longer be processed.
*/
for (i = 0; i < (MAX_RSS_CHAINS + 1); i++)
{
BNXE_LOCK_ENTER_INTR(pUM, i);
BNXE_LOCK_EXIT_INTR(pUM, i);
}
/* Disable the default interrupt... */
/* Disable the FCoE interrupt... */
/* Disable the RSS interrupts... */
}
{
int intrTypes = 0;
int intrTotalAlloc = 0;
int rc, i;
{
return B_FALSE;
}
if (numFIX <= 0)
{
return B_FALSE;
}
{
}
else if (numMSIX > 0)
{
}
else /* numFIX */
{
}
while (1)
{
/* allocate the default interrupt */
if (!BnxeIntrBlockAlloc(pUM,
0,
1,
{
goto BnxeIntrInit_alloc_fail;
}
{
/* only one interrupt allocated for fixed (default) */
break;
}
if (BnxeProtoFcoeAfex(pUM))
{
}
else
{
/* allocate the RSS interrupts */
{
if (!BnxeIntrBlockAlloc(pUM,
{
continue;
}
break;
}
{
goto BnxeIntrInit_alloc_fail;
}
}
/*
* Allocate the FCoE interrupt only if all available status blocks
* were not taken up by the RSS chains. If they were then the last
* status block (LM_NON_RSS_SB) is overloaded for both RSS and FCoE.
*/
{
{
if (!BnxeIntrBlockAlloc(pUM,
1,
{
goto BnxeIntrInit_alloc_fail;
}
}
else
{
/* to be safe, sets fcoeIntr.intrCount to 0 */
}
}
break;
{
return B_FALSE;
}
/* fall back to fixed a retry allocation */
intrTotalAlloc = 0;
}
{
}
else
{
/* fixed level (no rings)... */
}
if (!BnxeIntrAddHandlers(pUM))
{
return B_FALSE;
}
/* copy default priority and assume rest are the same (for mutex) */
return B_TRUE;
}
{
int i;
}