/*
* Copyright (c) 2009-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 "sfxge.h"
#include "efsys.h"
#include "efx.h"
#include "efx_mcdi.h"
#include "efx_regs_mcdi.h"
/* MAC 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 */
0x1000, /* 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 */
};
/*
* Notes on MCDI operation:
* ------------------------
* MCDI requests can be made in arbitrary thread context, and as a synchronous
* API must therefore block until the response is available from the MC, or
* a watchdog timeout occurs.
*
* This interacts badly with the limited number of worker threads (2 per CPU)
* used by the Solaris callout subsystem to invoke timeout handlers. If both
* worker threads are blocked (e.g. waiting for a condvar or mutex) then timeout
* processing is deadlocked on that CPU, causing system failure.
*
* For this reason the driver does not use event based MCDI completion, as this
* leads to numerous paths involving timeouts and reentrant GLDv3 entrypoints
* that result in a deadlocked system.
*/
/* Acquire exclusive access to MCDI for the duration of a request */
static void
{
}
}
/* Release ownership of MCDI on request completion */
static void
{
}
static void
{
"MCDI timeout", 0);
}
static void
{
/* Poll until request completes or timeout */
/* No response received yet */
if (ddi_get_lbolt() > timeout) {
/* Timeout expired */
goto fail;
}
/* Short delay to avoid excessive PCIe traffic */
}
/* Request completed (or polling failed) */
return;
fail:
/* Timeout before request completion */
}
static void
{
/* Issue request and poll for completion */
}
static void
{
}
static void
{
const char *reason;
if (eme == EFX_MCDI_EXCEPTION_MC_REBOOT)
reason = "MC_REBOOT";
else if (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT)
reason = "MC_BADASSERT";
else
reason = "MC_UNKNOWN";
/* sfxge_evq_t->se_lock held */
}
static size_t
{
size_t i;
}
" %08x", *words);
words++;
}
return (position);
}
static void
{
if (!sp->s_mcdi_logging)
return;
"sfc %04x:%02x:%02x.%02x %s%d MCDI RPC %s:",
0,
}
}
#endif /* EFSYS_OPT_MCDI_LOGGING */
int
{
int msg_buf_size;
int rc;
/* Allocate host DMA buffer for MCDI commands */
goto fail1;
#endif
goto fail2;
return (0);
return (rc);
}
void
{
}
int
{
int rc;
goto fail1;
}
goto fail2;
}
goto fail3;
}
/*
* Helpfully trigger a device reset in response to an MCDI_CMD_REBOOT
* Both ports will see ->emt_exception callbacks on the next MCDI poll
*/
/* sfxge_t->s_state_lock held */
"MC_REBOOT triggering restart", 0);
}
return (0);
return (rc);
}
int
{
int rc;
goto fail1;
}
goto fail2;
}
goto fail3;
}
/*
* Helpfully trigger a device reset in response to an MCDI_CMD_REBOOT
* Both ports will see ->emt_exception callbacks on the next MCDI poll
*/
/* sfxge_t->s_state_lock held */
"MC_REBOOT triggering restart", 0);
}
return (0);
return (rc);
}