sfxge_mac.c revision 49ef7e0638c8b771d8a136eae78b1c0f99acc8e0
/*
* 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.
*/
/*
* All efx_mac_*() must be after efx_port_init()
* LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
* to serialise against sfxge_restart()
*/
#include <sys/sysmacros.h>
#include "sfxge.h"
#include "efx.h"
#define SFXGE_MAC_POLL_PERIOD_MS 1000
/* MAC DMA attributes */
static ddi_device_acc_attr_t sfxge_mac_devacc = {
DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
};
static ddi_dma_attr_t sfxge_mac_dma_attr = {
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 */
};
static void
{
int i;
/* if no stats pending then they are already freshly updated */
return;
for (i = 0; i < tries; i++) {
/* Try to update the cached counters */
goto done;
}
return;
done:
}
static void
{
/*
* Update the statistics from the most recent DMA. This might race
* with an inflight dma, so retry once. Otherwise get mac stat
* values from the last mac_poll() or MC periodic stats.
*/
}
static void
{
/* Wait a max of 20 * 500us = 10ms */
}
static int
{
int rc;
unsigned int val;
if (rw != KSTAT_READ) {
goto fail1;
}
goto done;
knp += EFX_MAC_NSTATS;
knp++;
knp++;
knp++;
knp++;
knp++;
knp++;
knp++;
val = 0;
knp++;
done:
return (0);
return (rc);
}
static int
{
char name[MAXNAMELEN];
unsigned int id;
int rc;
/* Create the set */
goto fail1;
}
/* Initialise the named stats */
knp++;
}
return (0);
return (rc);
}
static void
{
/* Destroy the set */
}
void
{
/* Make sure the cached counter values are recent */
goto done;
done:
}
static void
sfxge_mac_poll(void *arg)
{
/* clears smp->sm_mac_stats_pend if appropriate */
if (smp->sm_mac_stats_pend)
/* This may sleep waiting for MCDI completion */
goto done;
/* Zero the memory */
/* Trigger upload the MAC statistics counters */
if (smp->sm_link_up &&
/* Wait for timeout or end of polling */
/* Timeout - poll if polling still enabled */
break;
}
}
}
done:
}
static void
{
/* Schedule a poll */
}
static void
{
/* Wait for link polling to cease */
/* Collect the final statistics. */
}
int
{
const efx_nic_cfg_t *encp;
unsigned char *bytes;
unsigned int n;
/* Create link poll taskq */
goto fail1;
}
goto fail2;
goto fail3;
/* Set the initial flow control values */
/*
* Determine the 'burnt-in' MAC address:
*
* A: if the "mac-address" property is set on our device node use that.
* B: otherwise, use the value from NVRAM.
*/
/* A: property */
"mac-address", &bytes, &n);
switch (err) {
case DDI_PROP_SUCCESS:
if (n == ETHERADDRL) {
goto done;
}
break;
default:
break;
}
/* B: NVRAM */
done:
/* Initialize the statistics */
goto fail4;
goto fail5;
return (0);
/* Tear down DMA setup */
/* Destroy the link poll taskq */
return (rc);
}
static int
{
int rc;
all_mulcst, brdcst)) != 0) {
goto fail1;
}
goto fail2;
}
return (0);
return (rc);
}
int
{
int rc;
goto fail1;
/*
* Set up the advertised capabilities that may have been asked for
* before the call to efx_port_init().
*/
goto fail2;
/* Set the SDU */
goto fail3;
goto fail4;
/* Set the unicast address */
goto fail5;
goto fail6;
if (!smp->sm_mac_stats_timer_reqd) {
SFXGE_MAC_POLL_PERIOD_MS, B_FALSE)) != 0)
goto fail7;
}
goto fail8;
/*
* Start link state polling. For hardware that reports link change
* events we still poll once to update the initial link state.
*/
return (0);
return (rc);
}
static void
{
char info[sizeof (": now 10000Mbps FULL duplex")];
return;
return;
switch (smp->sm_link_mode) {
case EFX_LINK_UNKNOWN:
case EFX_LINK_DOWN:
smp->sm_link_speed = 0;
break;
case EFX_LINK_10HDX:
case EFX_LINK_10FDX:
break;
case EFX_LINK_100HDX:
case EFX_LINK_100FDX:
break;
case EFX_LINK_1000HDX:
case EFX_LINK_1000FDX:
break;
case EFX_LINK_10000FDX:
break;
case EFX_LINK_40000FDX:
break;
default:
break;
}
"full" : "half";
/* Push link state update to the OS */
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
int
{
int rc;
goto done;
goto done;
goto fail1;
done:
return (0);
return (rc);
}
int
{
int rc;
if (type >= SFXGE_UNICST_NTYPES) {
goto fail1;
}
goto fail2;
}
switch (type) {
case SFXGE_UNICST_BIA:
break;
case SFXGE_UNICST_LAA:
if (!(smp->sm_laa_valid)) {
goto fail3;
}
break;
default:
break;
}
return (0);
return (rc);
}
int
{
int rc;
if (old_mac_valid)
goto done;
"unable to set unicast MAC filter");
goto fail1;
}
} else {
/* Older EF10 firmware requires a device start */
sfxge_stop(sp);
"unable to restart with a new MAC");
goto fail1;
}
}
goto fail1;
done:
return (0);
if (old_mac_valid)
else
return (rc);
}
int
{
int rc;
goto done;
goto fail1;
done:
return (0);
return (rc);
}
int
{
int i;
int rc;
if ((addr[0] & 0x1) == 0) {
goto fail1;
}
/* Check if the address is already in the list */
i = 0;
while (i < smp->sm_mcast_count) {
addr, ETHERADDRL) == 0)
goto done;
else
i++;
}
goto fail1;
}
/* Add to the list */
goto fail2;
done:
return (0);
smp->sm_mcast_count--;
return (rc);
}
int
{
int i;
int rc;
i = 0;
while (i < smp->sm_mcast_count) {
addr, ETHERADDRL) == 0) {
smp->sm_mcast_count--;
} else
i++;
}
goto fail1;
return (0);
return (rc);
}
void
{
/* If stopping in response to an MC reboot this may fail */
if (!smp->sm_mac_stats_timer_reqd)
smp->sm_link_speed = 0;
/* This may call MCDI */
}
void
{
/* Tear down the statistics */
smp->sm_mcast_count = 0;
/* Finish with PHY DMA memory */
/* Teardown the DMA */
/* Destroy the link poll taskq */
}