/*
* Copyright (c) 2008-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/ethernet.h>
#include "sfxge.h"
#include "efx.h"
/* Interrupt table DMA attributes */
DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
};
DMA_ATTR_V0, /* dma_attr_version */
0, /* dma_attr_addr_lo */
0xffffffffffffffffull, /* dma_attr_addr_hi */
0xffffffffffffffffull, /* dma_attr_count_max */
EFX_INTR_SIZE, /* dma_attr_align */
0xffffffff, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0xffffffffffffffffull, /* dma_attr_maxxfer */
0xffffffffffffffffull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
static unsigned int
{
unsigned int index;
int rc;
goto done;
}
goto done;
}
if (fatal) {
goto done;
}
if (qmask != 0) {
}
sip->si_zero_count = 0;
goto done;
}
/*
* interrupt, and poll all evqs for work. For subsequent ISR=0
* interrupts (the line must be shared in this case), just rearm the
* event queues to ensure we don't miss an interrupt.
*/
if (sip->si_zero_count++ == 0) {
}
} else {
}
}
done:
return (rc);
}
static unsigned int
{
int rc;
goto done;
}
do {
goto done;
}
if (fatal) {
goto done;
}
done:
return (rc);
}
static int
{
int add_index;
int en_index;
int err;
int rc;
/* Serialise all instances to avoid problems seen in bug31184. */
case EFX_INTR_MESSAGE:
break;
case EFX_INTR_LINE:
break;
default:
"bus_enable: unknown intr type (si_type=%d nalloc=%d)",
goto fail1;
}
/* Try to add the handlers */
unsigned int pri;
/* This cannot fail unless given invalid inputs. */
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_add_handler failed"
" err=%d (h=%p idx=%d nalloc=%d)",
goto fail2;
}
}
/* Get interrupt capabilities */
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_get_cap failed"
" err=%d (h=%p idx=%d nalloc=%d)",
if (err == DDI_EINVAL)
else if (err == DDI_ENOTSUP)
else
goto fail3;
}
/* Enable interrupts at the bus */
en_index = 0; /* Silence gcc */
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_block_enable failed"
" err=%d (table=%p nalloc=%d)",
goto fail4;
}
} else {
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_enable failed"
" err=%d (h=%p idx=%d nalloc=%d)",
goto fail4;
}
}
}
return (0);
/* Disable the enabled handlers */
while (--en_index >= 0) {
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_disable"
" failed err=%d (h=%p idx=%d nalloc=%d)",
}
}
}
/* Remove all handlers */
/* Remove remaining handlers */
while (--add_index >= 0) {
if (err != DDI_SUCCESS) {
"bus_enable: ddi_intr_remove_handler"
" failed err=%d (h=%p idx=%d nalloc=%d)",
}
}
return (rc);
}
static void
{
int index;
int err;
/* Serialise all instances to avoid problems seen in bug31184. */
/* Disable interrupts at the bus */
if (err != DDI_SUCCESS) {
"bus_disable: ddi_intr_block_disable"
" failed err=%d (table=%p nalloc=%d)",
}
} else {
while (--index >= 0) {
if (err != DDI_SUCCESS) {
"bus_disable: ddi_intr_disable"
" failed err=%d (h=%p idx=%d nalloc=%d)",
}
}
}
/* Remove all handlers */
while (--index >= 0) {
if (err != DDI_SUCCESS) {
"bus_disable: ddi_intr_remove_handler"
" failed err=%d (h=%p idx=%d nalloc=%d)",
}
}
}
static int
{
unsigned int index;
unsigned int count;
int rc;
/* Zero the memory */
/* Enable interrupts at the NIC */
goto fail1;
/* FIXME FIXME FIXME */
/* Disable interrupt test until supported on Huntington. */
return (0);
}
/* FIXME FIXME FIXME */
/* Test the interrupts */
mask = 0;
}
/* Wait for the tests to complete */
count = 0;
do {
/* Spin for 1 ms */
drv_usecwait(1000);
/*
* Check to see that all the test interrupts have been
* processed.
*/
goto done;
} while (++count < 20);
goto fail2;
done:
return (0);
PRIx64"). NIC is disabled",
/* Disable interrupts at the NIC */
return (rc);
}
static void
{
/* Disable interrupts at the NIC */
}
static inline unsigned
pow2_le(unsigned long n)
{
ASSERT3U(n, >, 0);
}
int
{
int err;
int rc;
int types;
int type;
int index;
unsigned int nalloc;
int navail;
#ifdef __sparc
/* PSARC 2007/453 */
"#msix-request", NULL, 0);
#endif
/* Get the map of supported interrupt types */
if (err != DDI_SUCCESS) {
"intr_init: ddi_intr_get_supported_types failed err=%d",
err);
if (err == DDI_EINVAL)
else if (err == DDI_INTR_NOTFOUND)
else
goto fail1;
}
/* Choose most favourable type */
if (types & DDI_INTR_TYPE_MSIX) {
} else {
}
/* Get the number of available interrupts */
navail = 0;
if (err != DDI_SUCCESS) {
"intr_init: ddi_intr_get_navail failed err=%d", err);
if (err == DDI_EINVAL)
else if (err == DDI_INTR_NOTFOUND)
else
goto fail2;
}
/* Double-check */
if (navail == 0) {
goto fail2;
}
/*
* Allow greater number of MSI-X interrupts than CPUs.
* This can be useful to prevent RX no desc drops; See task 32179.
* Limit non MSI-X interrupts to a single instance.
*/
if (type != DDI_INTR_TYPE_MSIX)
navail = 1;
else
/* Allocate a handle table */
/*
* Allocate interrupt handles.
* Serialise all device instances to avoid problems seen in bug31184.
*/
if (err != DDI_SUCCESS) {
"intr_init: ddi_intr_alloc failed err=%d"
" (navail=%d nalloc=%d)",
if (err == DDI_EINVAL)
else if (err == DDI_EAGAIN)
else if (err == DDI_INTR_NOTFOUND)
else
goto fail3;
}
/* Double-check */
goto fail3;
}
/* Round down to a power of 2 */
/* Free off any excess handles */
}
goto fail4;
/* Store the highest priority for convenience */
sip->si_intr_pri = 0;
goto fail5;
}
return (0);
/* Free interrupt handles */
while (--index >= 0) {
if (err != DDI_SUCCESS) {
"intr_init: ddi_intr_free failed err=%d"
" (h=%p idx=%d nalloc=%d)",
}
}
/* Free the handle table */
sip->si_table_size = 0;
/* Clear the interrupt type */
return (rc);
}
int
{
int rc;
/* Enable interrupts at the bus */
goto fail1;
/* Enable interrupts at the NIC */
goto fail2;
return (0);
/* Disable interrupts at the bus */
return (rc);
}
void
{
/* Disable interrupts at the NIC */
/* Disable interrupts at the bus */
}
void
{
int index;
int err;
/* Tear down dma setup */
/* Free interrupt handles */
while (--index >= 0) {
if (err != DDI_SUCCESS) {
"intr_fini: ddi_intr_free failed err=%d"
" (h=%p idx=%d nalloc=%d)",
}
}
/* Free the handle table */
sip->si_table_size = 0;
/* Clear the interrupt type */
}