f0188618f2
- Wrong integer type was specified. - Wrong or missing "access" specifier. The "access" specifier sometimes included the SYSCTL type, which it should not, except for procedural SYSCTL nodes. - Logical OR where binary OR was expected. - Properly assert the "access" argument passed to all SYSCTL macros, using the CTASSERT macro. This applies to both static- and dynamically created SYSCTLs. - Properly assert the the data type for both static and dynamic SYSCTLs. In the case of static SYSCTLs we only assert that the data pointed to by the SYSCTL data pointer has the correct size, hence there is no easy way to assert types in the C language outside a C-function. - Rewrote some code which doesn't pass a constant "access" specifier when creating dynamic SYSCTL nodes, which is now a requirement. - Updated "EXAMPLES" section in SYSCTL manual page. MFC after: 3 days Sponsored by: Mellanox Technologies
4202 lines
102 KiB
C
4202 lines
102 KiB
C
/*-
|
|
* Copyright(c) 2002-2011 Exar Corp.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification are permitted provided 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 and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the Exar Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* 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.
|
|
*/
|
|
/*$FreeBSD$*/
|
|
|
|
#include <dev/vxge/vxge.h>
|
|
|
|
static int vxge_pci_bd_no = -1;
|
|
static u32 vxge_drv_copyright = 0;
|
|
static u32 vxge_dev_ref_count = 0;
|
|
static u32 vxge_dev_req_reboot = 0;
|
|
|
|
static int vpath_selector[VXGE_HAL_MAX_VIRTUAL_PATHS] = \
|
|
{0, 1, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 31};
|
|
|
|
/*
|
|
* vxge_probe
|
|
* Probes for x3100 devices
|
|
*/
|
|
int
|
|
vxge_probe(device_t ndev)
|
|
{
|
|
int err = ENXIO;
|
|
|
|
u16 pci_bd_no = 0;
|
|
u16 pci_vendor_id = 0;
|
|
u16 pci_device_id = 0;
|
|
|
|
char adapter_name[64];
|
|
|
|
pci_vendor_id = pci_get_vendor(ndev);
|
|
if (pci_vendor_id != VXGE_PCI_VENDOR_ID)
|
|
goto _exit0;
|
|
|
|
pci_device_id = pci_get_device(ndev);
|
|
|
|
if (pci_device_id == VXGE_PCI_DEVICE_ID_TITAN_1) {
|
|
|
|
pci_bd_no = (pci_get_bus(ndev) | pci_get_slot(ndev));
|
|
|
|
snprintf(adapter_name, sizeof(adapter_name),
|
|
VXGE_ADAPTER_NAME, pci_get_revid(ndev));
|
|
device_set_desc_copy(ndev, adapter_name);
|
|
|
|
if (!vxge_drv_copyright) {
|
|
device_printf(ndev, VXGE_COPYRIGHT);
|
|
vxge_drv_copyright = 1;
|
|
}
|
|
|
|
if (vxge_dev_req_reboot == 0) {
|
|
vxge_pci_bd_no = pci_bd_no;
|
|
err = BUS_PROBE_DEFAULT;
|
|
} else {
|
|
if (pci_bd_no != vxge_pci_bd_no) {
|
|
vxge_pci_bd_no = pci_bd_no;
|
|
err = BUS_PROBE_DEFAULT;
|
|
}
|
|
}
|
|
}
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_attach
|
|
* Connects driver to the system if probe was success @ndev handle
|
|
*/
|
|
int
|
|
vxge_attach(device_t ndev)
|
|
{
|
|
int err = 0;
|
|
vxge_dev_t *vdev;
|
|
vxge_hal_device_t *hldev = NULL;
|
|
vxge_hal_device_attr_t device_attr;
|
|
vxge_free_resources_e error_level = VXGE_FREE_NONE;
|
|
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
/* Get per-ndev buffer */
|
|
vdev = (vxge_dev_t *) device_get_softc(ndev);
|
|
if (!vdev)
|
|
goto _exit0;
|
|
|
|
bzero(vdev, sizeof(vxge_dev_t));
|
|
|
|
vdev->ndev = ndev;
|
|
strlcpy(vdev->ndev_name, "vxge", sizeof(vdev->ndev_name));
|
|
|
|
err = vxge_driver_config(vdev);
|
|
if (err != 0)
|
|
goto _exit0;
|
|
|
|
/* Initialize HAL driver */
|
|
status = vxge_driver_init(vdev);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev, "Failed to initialize driver\n");
|
|
goto _exit0;
|
|
}
|
|
/* Enable PCI bus-master */
|
|
pci_enable_busmaster(ndev);
|
|
|
|
/* Allocate resources */
|
|
err = vxge_alloc_resources(vdev);
|
|
if (err != 0) {
|
|
device_printf(vdev->ndev, "resource allocation failed\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
err = vxge_device_hw_info_get(vdev);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_BAR2;
|
|
goto _exit0;
|
|
}
|
|
|
|
/* Get firmware default values for Device Configuration */
|
|
vxge_hal_device_config_default_get(vdev->device_config);
|
|
|
|
/* Customize Device Configuration based on User request */
|
|
vxge_vpath_config(vdev);
|
|
|
|
/* Allocate ISR resources */
|
|
err = vxge_alloc_isr_resources(vdev);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_ISR_RESOURCE;
|
|
device_printf(vdev->ndev, "isr resource allocation failed\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
/* HAL attributes */
|
|
device_attr.bar0 = (u8 *) vdev->pdev->bar_info[0];
|
|
device_attr.bar1 = (u8 *) vdev->pdev->bar_info[1];
|
|
device_attr.bar2 = (u8 *) vdev->pdev->bar_info[2];
|
|
device_attr.regh0 = (vxge_bus_res_t *) vdev->pdev->reg_map[0];
|
|
device_attr.regh1 = (vxge_bus_res_t *) vdev->pdev->reg_map[1];
|
|
device_attr.regh2 = (vxge_bus_res_t *) vdev->pdev->reg_map[2];
|
|
device_attr.irqh = (pci_irq_h) vdev->config.isr_info[0].irq_handle;
|
|
device_attr.cfgh = vdev->pdev;
|
|
device_attr.pdev = vdev->pdev;
|
|
|
|
/* Initialize HAL Device */
|
|
status = vxge_hal_device_initialize((vxge_hal_device_h *) &hldev,
|
|
&device_attr, vdev->device_config);
|
|
if (status != VXGE_HAL_OK) {
|
|
error_level = VXGE_FREE_ISR_RESOURCE;
|
|
device_printf(vdev->ndev, "hal device initialization failed\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->devh = hldev;
|
|
vxge_hal_device_private_set(hldev, vdev);
|
|
|
|
if (vdev->is_privilaged) {
|
|
err = vxge_firmware_verify(vdev);
|
|
if (err != 0) {
|
|
vxge_dev_req_reboot = 1;
|
|
error_level = VXGE_FREE_TERMINATE_DEVICE;
|
|
goto _exit0;
|
|
}
|
|
}
|
|
|
|
/* Allocate memory for vpath */
|
|
vdev->vpaths = (vxge_vpath_t *)
|
|
vxge_mem_alloc(vdev->no_of_vpath * sizeof(vxge_vpath_t));
|
|
|
|
if (vdev->vpaths == NULL) {
|
|
error_level = VXGE_FREE_TERMINATE_DEVICE;
|
|
device_printf(vdev->ndev, "vpath memory allocation failed\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->no_of_func = 1;
|
|
if (vdev->is_privilaged) {
|
|
|
|
vxge_hal_func_mode_count(vdev->devh,
|
|
vdev->config.hw_info.function_mode, &vdev->no_of_func);
|
|
|
|
vxge_bw_priority_config(vdev);
|
|
}
|
|
|
|
/* Initialize mutexes */
|
|
vxge_mutex_init(vdev);
|
|
|
|
/* Initialize Media */
|
|
vxge_media_init(vdev);
|
|
|
|
err = vxge_ifp_setup(ndev);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_MEDIA;
|
|
device_printf(vdev->ndev, "setting up interface failed\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
err = vxge_isr_setup(vdev);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_INTERFACE;
|
|
device_printf(vdev->ndev,
|
|
"failed to associate interrupt handler with device\n");
|
|
goto _exit0;
|
|
}
|
|
vxge_device_hw_info_print(vdev);
|
|
vdev->is_active = TRUE;
|
|
|
|
_exit0:
|
|
if (error_level) {
|
|
vxge_free_resources(ndev, error_level);
|
|
err = ENXIO;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_detach
|
|
* Detaches driver from the Kernel subsystem
|
|
*/
|
|
int
|
|
vxge_detach(device_t ndev)
|
|
{
|
|
vxge_dev_t *vdev;
|
|
|
|
vdev = (vxge_dev_t *) device_get_softc(ndev);
|
|
if (vdev->is_active) {
|
|
vdev->is_active = FALSE;
|
|
vxge_stop(vdev);
|
|
vxge_free_resources(ndev, VXGE_FREE_ALL);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* vxge_shutdown
|
|
* To shutdown device before system shutdown
|
|
*/
|
|
int
|
|
vxge_shutdown(device_t ndev)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) device_get_softc(ndev);
|
|
vxge_stop(vdev);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* vxge_init
|
|
* Initialize the interface
|
|
*/
|
|
void
|
|
vxge_init(void *vdev_ptr)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) vdev_ptr;
|
|
|
|
VXGE_DRV_LOCK(vdev);
|
|
vxge_init_locked(vdev);
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
}
|
|
|
|
/*
|
|
* vxge_init_locked
|
|
* Initialize the interface
|
|
*/
|
|
void
|
|
vxge_init_locked(vxge_dev_t *vdev)
|
|
{
|
|
int i, err = EINVAL;
|
|
vxge_hal_device_t *hldev = vdev->devh;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
vxge_hal_vpath_h vpath_handle;
|
|
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
/* If device is in running state, initializing is not required */
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
|
goto _exit0;
|
|
|
|
VXGE_DRV_LOCK_ASSERT(vdev);
|
|
|
|
/* Opening vpaths */
|
|
err = vxge_vpath_open(vdev);
|
|
if (err != 0)
|
|
goto _exit1;
|
|
|
|
if (vdev->config.rth_enable) {
|
|
status = vxge_rth_config(vdev);
|
|
if (status != VXGE_HAL_OK)
|
|
goto _exit1;
|
|
}
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
/* check initial mtu before enabling the device */
|
|
status = vxge_hal_device_mtu_check(vpath_handle, ifp->if_mtu);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"invalid mtu size %u specified\n", ifp->if_mtu);
|
|
goto _exit1;
|
|
}
|
|
|
|
status = vxge_hal_vpath_mtu_set(vpath_handle, ifp->if_mtu);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"setting mtu in device failed\n");
|
|
goto _exit1;
|
|
}
|
|
}
|
|
|
|
/* Enable HAL device */
|
|
status = vxge_hal_device_enable(hldev);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev, "failed to enable device\n");
|
|
goto _exit1;
|
|
}
|
|
|
|
if (vdev->config.intr_mode == VXGE_HAL_INTR_MODE_MSIX)
|
|
vxge_msix_enable(vdev);
|
|
|
|
/* Checksum capability */
|
|
ifp->if_hwassist = 0;
|
|
if (ifp->if_capenable & IFCAP_TXCSUM)
|
|
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
|
|
|
|
if (ifp->if_capenable & IFCAP_TSO4)
|
|
ifp->if_hwassist |= CSUM_TSO;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
/* Enabling mcast for all vpath */
|
|
vxge_hal_vpath_mcast_enable(vpath_handle);
|
|
|
|
/* Enabling bcast for all vpath */
|
|
status = vxge_hal_vpath_bcast_enable(vpath_handle);
|
|
if (status != VXGE_HAL_OK)
|
|
device_printf(vdev->ndev,
|
|
"can't enable bcast on vpath (%d)\n", i);
|
|
}
|
|
|
|
/* Enable interrupts */
|
|
vxge_hal_device_intr_enable(vdev->devh);
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
bzero(&(vdev->vpaths[i].driver_stats),
|
|
sizeof(vxge_drv_stats_t));
|
|
status = vxge_hal_vpath_enable(vpath_handle);
|
|
if (status != VXGE_HAL_OK)
|
|
goto _exit2;
|
|
}
|
|
|
|
vxge_os_mdelay(1000);
|
|
|
|
/* Device is initialized */
|
|
vdev->is_initialized = TRUE;
|
|
|
|
/* Now inform the stack we're ready */
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
|
|
|
goto _exit0;
|
|
|
|
_exit2:
|
|
vxge_hal_device_intr_disable(vdev->devh);
|
|
vxge_hal_device_disable(hldev);
|
|
|
|
_exit1:
|
|
vxge_vpath_close(vdev);
|
|
|
|
_exit0:
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* vxge_driver_init
|
|
* Initializes HAL driver
|
|
*/
|
|
vxge_hal_status_e
|
|
vxge_driver_init(vxge_dev_t *vdev)
|
|
{
|
|
vxge_hal_uld_cbs_t uld_callbacks;
|
|
vxge_hal_driver_config_t driver_config;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
/* Initialize HAL driver */
|
|
if (!vxge_dev_ref_count) {
|
|
bzero(&uld_callbacks, sizeof(vxge_hal_uld_cbs_t));
|
|
bzero(&driver_config, sizeof(vxge_hal_driver_config_t));
|
|
|
|
uld_callbacks.link_up = vxge_link_up;
|
|
uld_callbacks.link_down = vxge_link_down;
|
|
uld_callbacks.crit_err = vxge_crit_error;
|
|
uld_callbacks.sched_timer = NULL;
|
|
uld_callbacks.xpak_alarm_log = NULL;
|
|
|
|
status = vxge_hal_driver_initialize(&driver_config,
|
|
&uld_callbacks);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"failed to initialize driver\n");
|
|
goto _exit0;
|
|
}
|
|
}
|
|
vxge_hal_driver_debug_set(VXGE_TRACE);
|
|
vxge_dev_ref_count++;
|
|
|
|
_exit0:
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* vxge_driver_config
|
|
*/
|
|
int
|
|
vxge_driver_config(vxge_dev_t *vdev)
|
|
{
|
|
int i, err = 0;
|
|
char temp_buffer[30];
|
|
|
|
vxge_bw_info_t bw_info;
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.no_of_vpath", vdev->config,
|
|
no_of_vpath, VXGE_DEFAULT_USER_HARDCODED);
|
|
|
|
if (vdev->config.no_of_vpath == VXGE_DEFAULT_USER_HARDCODED)
|
|
vdev->config.no_of_vpath = mp_ncpus;
|
|
|
|
if (vdev->config.no_of_vpath <= 0) {
|
|
err = EINVAL;
|
|
device_printf(vdev->ndev,
|
|
"Failed to load driver, \
|
|
invalid config : \'no_of_vpath\'\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.intr_coalesce", vdev->config,
|
|
intr_coalesce, VXGE_DEFAULT_CONFIG_DISABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.rth_enable", vdev->config,
|
|
rth_enable, VXGE_DEFAULT_CONFIG_ENABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.rth_bkt_sz", vdev->config,
|
|
rth_bkt_sz, VXGE_DEFAULT_RTH_BUCKET_SIZE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.lro_enable", vdev->config,
|
|
lro_enable, VXGE_DEFAULT_CONFIG_ENABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.tso_enable", vdev->config,
|
|
tso_enable, VXGE_DEFAULT_CONFIG_ENABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.tx_steering", vdev->config,
|
|
tx_steering, VXGE_DEFAULT_CONFIG_DISABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.msix_enable", vdev->config,
|
|
intr_mode, VXGE_HAL_INTR_MODE_MSIX);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.ifqmaxlen", vdev->config,
|
|
ifq_maxlen, VXGE_DEFAULT_CONFIG_IFQ_MAXLEN);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.port_mode", vdev->config,
|
|
port_mode, VXGE_DEFAULT_CONFIG_VALUE);
|
|
|
|
if (vdev->config.port_mode == VXGE_DEFAULT_USER_HARDCODED)
|
|
vdev->config.port_mode = VXGE_DEFAULT_CONFIG_VALUE;
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.l2_switch", vdev->config,
|
|
l2_switch, VXGE_DEFAULT_CONFIG_VALUE);
|
|
|
|
if (vdev->config.l2_switch == VXGE_DEFAULT_USER_HARDCODED)
|
|
vdev->config.l2_switch = VXGE_DEFAULT_CONFIG_VALUE;
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.fw_upgrade", vdev->config,
|
|
fw_option, VXGE_FW_UPGRADE_ALL);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.low_latency", vdev->config,
|
|
low_latency, VXGE_DEFAULT_CONFIG_DISABLE);
|
|
|
|
VXGE_GET_PARAM("hint.vxge.0.func_mode", vdev->config,
|
|
function_mode, VXGE_DEFAULT_CONFIG_VALUE);
|
|
|
|
if (vdev->config.function_mode == VXGE_DEFAULT_USER_HARDCODED)
|
|
vdev->config.function_mode = VXGE_DEFAULT_CONFIG_VALUE;
|
|
|
|
if (!(is_multi_func(vdev->config.function_mode) ||
|
|
is_single_func(vdev->config.function_mode)))
|
|
vdev->config.function_mode = VXGE_DEFAULT_CONFIG_VALUE;
|
|
|
|
for (i = 0; i < VXGE_HAL_MAX_FUNCTIONS; i++) {
|
|
|
|
bw_info.func_id = i;
|
|
|
|
sprintf(temp_buffer, "hint.vxge.0.bandwidth_%d", i);
|
|
VXGE_GET_PARAM(temp_buffer, bw_info,
|
|
bandwidth, VXGE_DEFAULT_USER_HARDCODED);
|
|
|
|
if (bw_info.bandwidth == VXGE_DEFAULT_USER_HARDCODED)
|
|
bw_info.bandwidth = VXGE_HAL_VPATH_BW_LIMIT_DEFAULT;
|
|
|
|
sprintf(temp_buffer, "hint.vxge.0.priority_%d", i);
|
|
VXGE_GET_PARAM(temp_buffer, bw_info,
|
|
priority, VXGE_DEFAULT_USER_HARDCODED);
|
|
|
|
if (bw_info.priority == VXGE_DEFAULT_USER_HARDCODED)
|
|
bw_info.priority = VXGE_HAL_VPATH_PRIORITY_DEFAULT;
|
|
|
|
vxge_os_memcpy(&vdev->config.bw_info[i], &bw_info,
|
|
sizeof(vxge_bw_info_t));
|
|
}
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_stop
|
|
*/
|
|
void
|
|
vxge_stop(vxge_dev_t *vdev)
|
|
{
|
|
VXGE_DRV_LOCK(vdev);
|
|
vxge_stop_locked(vdev);
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
}
|
|
|
|
/*
|
|
* vxge_stop_locked
|
|
* Common code for both stop and part of reset.
|
|
* disables device, interrupts and closes vpaths handle
|
|
*/
|
|
void
|
|
vxge_stop_locked(vxge_dev_t *vdev)
|
|
{
|
|
u64 adapter_status = 0;
|
|
vxge_hal_status_e status;
|
|
vxge_hal_device_t *hldev = vdev->devh;
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
VXGE_DRV_LOCK_ASSERT(vdev);
|
|
|
|
/* If device is not in "Running" state, return */
|
|
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
|
|
return;
|
|
|
|
/* Set appropriate flags */
|
|
vdev->is_initialized = FALSE;
|
|
hldev->link_state = VXGE_HAL_LINK_NONE;
|
|
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
|
|
if_link_state_change(ifp, LINK_STATE_DOWN);
|
|
|
|
/* Disable interrupts */
|
|
vxge_hal_device_intr_disable(hldev);
|
|
|
|
/* Disable HAL device */
|
|
status = vxge_hal_device_disable(hldev);
|
|
if (status != VXGE_HAL_OK) {
|
|
vxge_hal_device_status(hldev, &adapter_status);
|
|
device_printf(vdev->ndev,
|
|
"adapter status: 0x%llx\n", adapter_status);
|
|
}
|
|
|
|
/* reset vpaths */
|
|
vxge_vpath_reset(vdev);
|
|
|
|
vxge_os_mdelay(1000);
|
|
|
|
/* Close Vpaths */
|
|
vxge_vpath_close(vdev);
|
|
}
|
|
|
|
void
|
|
vxge_send(ifnet_t ifp)
|
|
{
|
|
vxge_vpath_t *vpath;
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
|
|
vpath = &(vdev->vpaths[0]);
|
|
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
|
|
if (VXGE_TX_TRYLOCK(vpath)) {
|
|
vxge_send_locked(ifp, vpath);
|
|
VXGE_TX_UNLOCK(vpath);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
vxge_send_locked(ifnet_t ifp, vxge_vpath_t *vpath)
|
|
{
|
|
mbuf_t m_head = NULL;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
VXGE_TX_LOCK_ASSERT(vpath);
|
|
|
|
if ((!vdev->is_initialized) ||
|
|
((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
|
|
IFF_DRV_RUNNING))
|
|
return;
|
|
|
|
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
|
|
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
|
|
if (m_head == NULL)
|
|
break;
|
|
|
|
if (vxge_xmit(ifp, vpath, &m_head)) {
|
|
if (m_head == NULL)
|
|
break;
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
|
|
VXGE_DRV_STATS(vpath, tx_again);
|
|
break;
|
|
}
|
|
/* Send a copy of the frame to the BPF listener */
|
|
ETHER_BPF_MTAP(ifp, m_head);
|
|
}
|
|
}
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
|
|
int
|
|
vxge_mq_send(ifnet_t ifp, mbuf_t m_head)
|
|
{
|
|
int i = 0, err = 0;
|
|
|
|
vxge_vpath_t *vpath;
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
|
|
if (vdev->config.tx_steering) {
|
|
i = vxge_vpath_get(vdev, m_head);
|
|
} else if ((m_head->m_flags & M_FLOWID) != 0) {
|
|
i = m_head->m_pkthdr.flowid % vdev->no_of_vpath;
|
|
}
|
|
|
|
vpath = &(vdev->vpaths[i]);
|
|
if (VXGE_TX_TRYLOCK(vpath)) {
|
|
err = vxge_mq_send_locked(ifp, vpath, m_head);
|
|
VXGE_TX_UNLOCK(vpath);
|
|
} else
|
|
err = drbr_enqueue(ifp, vpath->br, m_head);
|
|
|
|
return (err);
|
|
}
|
|
|
|
static inline int
|
|
vxge_mq_send_locked(ifnet_t ifp, vxge_vpath_t *vpath, mbuf_t m_head)
|
|
{
|
|
int err = 0;
|
|
mbuf_t next = NULL;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
VXGE_TX_LOCK_ASSERT(vpath);
|
|
|
|
if ((!vdev->is_initialized) ||
|
|
((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
|
|
IFF_DRV_RUNNING)) {
|
|
err = drbr_enqueue(ifp, vpath->br, m_head);
|
|
goto _exit0;
|
|
}
|
|
if (m_head == NULL) {
|
|
next = drbr_dequeue(ifp, vpath->br);
|
|
} else if (drbr_needs_enqueue(ifp, vpath->br)) {
|
|
if ((err = drbr_enqueue(ifp, vpath->br, m_head)) != 0)
|
|
goto _exit0;
|
|
next = drbr_dequeue(ifp, vpath->br);
|
|
} else
|
|
next = m_head;
|
|
|
|
/* Process the queue */
|
|
while (next != NULL) {
|
|
if ((err = vxge_xmit(ifp, vpath, &next)) != 0) {
|
|
if (next == NULL)
|
|
break;
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
err = drbr_enqueue(ifp, vpath->br, next);
|
|
VXGE_DRV_STATS(vpath, tx_again);
|
|
break;
|
|
}
|
|
if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len);
|
|
if (next->m_flags & M_MCAST)
|
|
if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
|
|
|
|
/* Send a copy of the frame to the BPF listener */
|
|
ETHER_BPF_MTAP(ifp, next);
|
|
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
|
|
break;
|
|
|
|
next = drbr_dequeue(ifp, vpath->br);
|
|
}
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
void
|
|
vxge_mq_qflush(ifnet_t ifp)
|
|
{
|
|
int i;
|
|
mbuf_t m_head;
|
|
vxge_vpath_t *vpath;
|
|
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath = &(vdev->vpaths[i]);
|
|
if (!vpath->handle)
|
|
continue;
|
|
|
|
VXGE_TX_LOCK(vpath);
|
|
while ((m_head = buf_ring_dequeue_sc(vpath->br)) != NULL)
|
|
vxge_free_packet(m_head);
|
|
|
|
VXGE_TX_UNLOCK(vpath);
|
|
}
|
|
if_qflush(ifp);
|
|
}
|
|
#endif
|
|
|
|
static inline int
|
|
vxge_xmit(ifnet_t ifp, vxge_vpath_t *vpath, mbuf_t *m_headp)
|
|
{
|
|
int err, num_segs = 0;
|
|
u32 txdl_avail, dma_index, tagged = 0;
|
|
|
|
dma_addr_t dma_addr;
|
|
bus_size_t dma_sizes;
|
|
|
|
void *dtr_priv;
|
|
vxge_txdl_priv_t *txdl_priv;
|
|
vxge_hal_txdl_h txdlh;
|
|
vxge_hal_status_e status;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
VXGE_DRV_STATS(vpath, tx_xmit);
|
|
|
|
txdl_avail = vxge_hal_fifo_free_txdl_count_get(vpath->handle);
|
|
if (txdl_avail < VXGE_TX_LOW_THRESHOLD) {
|
|
|
|
VXGE_DRV_STATS(vpath, tx_low_dtr_cnt);
|
|
err = ENOBUFS;
|
|
goto _exit0;
|
|
}
|
|
|
|
/* Reserve descriptors */
|
|
status = vxge_hal_fifo_txdl_reserve(vpath->handle, &txdlh, &dtr_priv);
|
|
if (status != VXGE_HAL_OK) {
|
|
VXGE_DRV_STATS(vpath, tx_reserve_failed);
|
|
err = ENOBUFS;
|
|
goto _exit0;
|
|
}
|
|
|
|
/* Update Tx private structure for this descriptor */
|
|
txdl_priv = (vxge_txdl_priv_t *) dtr_priv;
|
|
|
|
/*
|
|
* Map the packet for DMA.
|
|
* Returns number of segments through num_segs.
|
|
*/
|
|
err = vxge_dma_mbuf_coalesce(vpath->dma_tag_tx, txdl_priv->dma_map,
|
|
m_headp, txdl_priv->dma_buffers, &num_segs);
|
|
|
|
if (vpath->driver_stats.tx_max_frags < num_segs)
|
|
vpath->driver_stats.tx_max_frags = num_segs;
|
|
|
|
if (err == ENOMEM) {
|
|
VXGE_DRV_STATS(vpath, tx_no_dma_setup);
|
|
vxge_hal_fifo_txdl_free(vpath->handle, txdlh);
|
|
goto _exit0;
|
|
} else if (err != 0) {
|
|
vxge_free_packet(*m_headp);
|
|
VXGE_DRV_STATS(vpath, tx_no_dma_setup);
|
|
vxge_hal_fifo_txdl_free(vpath->handle, txdlh);
|
|
goto _exit0;
|
|
}
|
|
|
|
txdl_priv->mbuf_pkt = *m_headp;
|
|
|
|
/* Set VLAN tag in descriptor only if this packet has it */
|
|
if ((*m_headp)->m_flags & M_VLANTAG)
|
|
vxge_hal_fifo_txdl_vlan_set(txdlh,
|
|
(*m_headp)->m_pkthdr.ether_vtag);
|
|
|
|
/* Set descriptor buffer for header and each fragment/segment */
|
|
for (dma_index = 0; dma_index < num_segs; dma_index++) {
|
|
|
|
dma_sizes = txdl_priv->dma_buffers[dma_index].ds_len;
|
|
dma_addr = htole64(txdl_priv->dma_buffers[dma_index].ds_addr);
|
|
|
|
vxge_hal_fifo_txdl_buffer_set(vpath->handle, txdlh, dma_index,
|
|
dma_addr, dma_sizes);
|
|
}
|
|
|
|
/* Pre-write Sync of mapping */
|
|
bus_dmamap_sync(vpath->dma_tag_tx, txdl_priv->dma_map,
|
|
BUS_DMASYNC_PREWRITE);
|
|
|
|
if ((*m_headp)->m_pkthdr.csum_flags & CSUM_TSO) {
|
|
if ((*m_headp)->m_pkthdr.tso_segsz) {
|
|
VXGE_DRV_STATS(vpath, tx_tso);
|
|
vxge_hal_fifo_txdl_lso_set(txdlh,
|
|
VXGE_HAL_FIFO_LSO_FRM_ENCAP_AUTO,
|
|
(*m_headp)->m_pkthdr.tso_segsz);
|
|
}
|
|
}
|
|
|
|
/* Checksum */
|
|
if (ifp->if_hwassist > 0) {
|
|
vxge_hal_fifo_txdl_cksum_set_bits(txdlh,
|
|
VXGE_HAL_FIFO_TXD_TX_CKO_IPV4_EN |
|
|
VXGE_HAL_FIFO_TXD_TX_CKO_TCP_EN |
|
|
VXGE_HAL_FIFO_TXD_TX_CKO_UDP_EN);
|
|
}
|
|
|
|
if ((vxge_hal_device_check_id(vdev->devh) == VXGE_HAL_CARD_TITAN_1A) &&
|
|
(vdev->hw_fw_version >= VXGE_FW_VERSION(1, 8, 0)))
|
|
tagged = 1;
|
|
|
|
vxge_hal_fifo_txdl_post(vpath->handle, txdlh, tagged);
|
|
VXGE_DRV_STATS(vpath, tx_posted);
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_tx_replenish
|
|
* Allocate buffers and set them into descriptors for later use
|
|
*/
|
|
/* ARGSUSED */
|
|
vxge_hal_status_e
|
|
vxge_tx_replenish(vxge_hal_vpath_h vpath_handle, vxge_hal_txdl_h txdlh,
|
|
void *dtr_priv, u32 dtr_index, void *userdata, vxge_hal_reopen_e reopen)
|
|
{
|
|
int err = 0;
|
|
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_txdl_priv_t *txdl_priv = (vxge_txdl_priv_t *) dtr_priv;
|
|
|
|
err = bus_dmamap_create(vpath->dma_tag_tx, BUS_DMA_NOWAIT,
|
|
&txdl_priv->dma_map);
|
|
|
|
return ((err == 0) ? VXGE_HAL_OK : VXGE_HAL_FAIL);
|
|
}
|
|
|
|
/*
|
|
* vxge_tx_compl
|
|
* If the interrupt is due to Tx completion, free the sent buffer
|
|
*/
|
|
vxge_hal_status_e
|
|
vxge_tx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_txdl_h txdlh,
|
|
void *dtr_priv, vxge_hal_fifo_tcode_e t_code, void *userdata)
|
|
{
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
vxge_txdl_priv_t *txdl_priv;
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
VXGE_TX_LOCK(vpath);
|
|
|
|
/*
|
|
* For each completed descriptor
|
|
* Get private structure, free buffer, do unmapping, and free descriptor
|
|
*/
|
|
|
|
do {
|
|
VXGE_DRV_STATS(vpath, tx_compl);
|
|
if (t_code != VXGE_HAL_FIFO_T_CODE_OK) {
|
|
device_printf(vdev->ndev, "tx transfer code %d\n",
|
|
t_code);
|
|
|
|
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
|
|
VXGE_DRV_STATS(vpath, tx_tcode);
|
|
vxge_hal_fifo_handle_tcode(vpath_handle, txdlh, t_code);
|
|
}
|
|
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
|
|
txdl_priv = (vxge_txdl_priv_t *) dtr_priv;
|
|
|
|
bus_dmamap_unload(vpath->dma_tag_tx, txdl_priv->dma_map);
|
|
|
|
vxge_free_packet(txdl_priv->mbuf_pkt);
|
|
vxge_hal_fifo_txdl_free(vpath->handle, txdlh);
|
|
|
|
} while (vxge_hal_fifo_txdl_next_completed(vpath_handle, &txdlh,
|
|
&dtr_priv, &t_code) == VXGE_HAL_OK);
|
|
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
VXGE_TX_UNLOCK(vpath);
|
|
|
|
return (status);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
vxge_tx_term(vxge_hal_vpath_h vpath_handle, vxge_hal_txdl_h txdlh,
|
|
void *dtr_priv, vxge_hal_txdl_state_e state,
|
|
void *userdata, vxge_hal_reopen_e reopen)
|
|
{
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_txdl_priv_t *txdl_priv = (vxge_txdl_priv_t *) dtr_priv;
|
|
|
|
if (state != VXGE_HAL_TXDL_STATE_POSTED)
|
|
return;
|
|
|
|
if (txdl_priv != NULL) {
|
|
bus_dmamap_sync(vpath->dma_tag_tx, txdl_priv->dma_map,
|
|
BUS_DMASYNC_POSTWRITE);
|
|
|
|
bus_dmamap_unload(vpath->dma_tag_tx, txdl_priv->dma_map);
|
|
bus_dmamap_destroy(vpath->dma_tag_tx, txdl_priv->dma_map);
|
|
vxge_free_packet(txdl_priv->mbuf_pkt);
|
|
}
|
|
|
|
/* Free the descriptor */
|
|
vxge_hal_fifo_txdl_free(vpath->handle, txdlh);
|
|
}
|
|
|
|
/*
|
|
* vxge_rx_replenish
|
|
* Allocate buffers and set them into descriptors for later use
|
|
*/
|
|
/* ARGSUSED */
|
|
vxge_hal_status_e
|
|
vxge_rx_replenish(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
|
|
void *dtr_priv, u32 dtr_index, void *userdata, vxge_hal_reopen_e reopen)
|
|
{
|
|
int err = 0;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_rxd_priv_t *rxd_priv = (vxge_rxd_priv_t *) dtr_priv;
|
|
|
|
/* Create DMA map for these descriptors */
|
|
err = bus_dmamap_create(vpath->dma_tag_rx, BUS_DMA_NOWAIT,
|
|
&rxd_priv->dma_map);
|
|
if (err == 0) {
|
|
if (vxge_rx_rxd_1b_set(vpath, rxdh, dtr_priv)) {
|
|
bus_dmamap_destroy(vpath->dma_tag_rx,
|
|
rxd_priv->dma_map);
|
|
status = VXGE_HAL_FAIL;
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* vxge_rx_compl
|
|
*/
|
|
vxge_hal_status_e
|
|
vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
|
|
void *dtr_priv, u8 t_code, void *userdata)
|
|
{
|
|
mbuf_t mbuf_up;
|
|
|
|
vxge_rxd_priv_t *rxd_priv;
|
|
vxge_hal_ring_rxd_info_t ext_info;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
struct lro_entry *queued = NULL;
|
|
struct lro_ctrl *lro = &vpath->lro;
|
|
|
|
/* get the interface pointer */
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
do {
|
|
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
|
vxge_hal_ring_rxd_post(vpath_handle, rxdh);
|
|
status = VXGE_HAL_FAIL;
|
|
break;
|
|
}
|
|
|
|
VXGE_DRV_STATS(vpath, rx_compl);
|
|
rxd_priv = (vxge_rxd_priv_t *) dtr_priv;
|
|
|
|
/* Gets details of mbuf i.e., packet length */
|
|
vxge_rx_rxd_1b_get(vpath, rxdh, dtr_priv);
|
|
|
|
/*
|
|
* Prepare one buffer to send it to upper layer Since upper
|
|
* layer frees the buffer do not use rxd_priv->mbuf_pkt.
|
|
* Meanwhile prepare a new buffer, do mapping, use with the
|
|
* current descriptor and post descriptor back to ring vpath
|
|
*/
|
|
mbuf_up = rxd_priv->mbuf_pkt;
|
|
if (t_code != VXGE_HAL_RING_RXD_T_CODE_OK) {
|
|
|
|
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
|
|
VXGE_DRV_STATS(vpath, rx_tcode);
|
|
status = vxge_hal_ring_handle_tcode(vpath_handle,
|
|
rxdh, t_code);
|
|
|
|
/*
|
|
* If transfer code is not for unknown protocols and
|
|
* vxge_hal_device_handle_tcode is NOT returned
|
|
* VXGE_HAL_OK
|
|
* drop this packet and increment rx_tcode stats
|
|
*/
|
|
if ((status != VXGE_HAL_OK) &&
|
|
(t_code != VXGE_HAL_RING_T_CODE_L3_PKT_ERR)) {
|
|
|
|
vxge_free_packet(mbuf_up);
|
|
vxge_hal_ring_rxd_post(vpath_handle, rxdh);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (vxge_rx_rxd_1b_set(vpath, rxdh, dtr_priv)) {
|
|
/*
|
|
* If unable to allocate buffer, post descriptor back
|
|
* to vpath for future processing of same packet.
|
|
*/
|
|
vxge_hal_ring_rxd_post(vpath_handle, rxdh);
|
|
continue;
|
|
}
|
|
|
|
/* Get the extended information */
|
|
vxge_hal_ring_rxd_1b_info_get(vpath_handle, rxdh, &ext_info);
|
|
|
|
/* post descriptor with newly allocated mbuf back to vpath */
|
|
vxge_hal_ring_rxd_post(vpath_handle, rxdh);
|
|
vpath->rxd_posted++;
|
|
|
|
if (vpath->rxd_posted % VXGE_RXD_REPLENISH_COUNT == 0)
|
|
vxge_hal_ring_rxd_post_post_db(vpath_handle);
|
|
|
|
/*
|
|
* Set successfully computed checksums in the mbuf.
|
|
* Leave the rest to the stack to be reverified.
|
|
*/
|
|
vxge_rx_checksum(ext_info, mbuf_up);
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
mbuf_up->m_flags |= M_FLOWID;
|
|
mbuf_up->m_pkthdr.flowid = vpath->vp_index;
|
|
#endif
|
|
/* Post-Read sync for buffers */
|
|
bus_dmamap_sync(vpath->dma_tag_rx, rxd_priv->dma_map,
|
|
BUS_DMASYNC_POSTREAD);
|
|
|
|
vxge_rx_input(ifp, mbuf_up, vpath);
|
|
|
|
} while (vxge_hal_ring_rxd_next_completed(vpath_handle, &rxdh,
|
|
&dtr_priv, &t_code) == VXGE_HAL_OK);
|
|
|
|
/* Flush any outstanding LRO work */
|
|
if (vpath->lro_enable && vpath->lro.lro_cnt) {
|
|
while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
|
|
SLIST_REMOVE_HEAD(&lro->lro_active, next);
|
|
tcp_lro_flush(lro, queued);
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
static inline void
|
|
vxge_rx_input(ifnet_t ifp, mbuf_t mbuf_up, vxge_vpath_t *vpath)
|
|
{
|
|
if (vpath->lro_enable && vpath->lro.lro_cnt) {
|
|
if (tcp_lro_rx(&vpath->lro, mbuf_up, 0) == 0)
|
|
return;
|
|
}
|
|
(*ifp->if_input) (ifp, mbuf_up);
|
|
}
|
|
|
|
static inline void
|
|
vxge_rx_checksum(vxge_hal_ring_rxd_info_t ext_info, mbuf_t mbuf_up)
|
|
{
|
|
|
|
if (!(ext_info.proto & VXGE_HAL_FRAME_PROTO_IP_FRAG) &&
|
|
(ext_info.proto & VXGE_HAL_FRAME_PROTO_TCP_OR_UDP) &&
|
|
ext_info.l3_cksum_valid && ext_info.l4_cksum_valid) {
|
|
|
|
mbuf_up->m_pkthdr.csum_data = htons(0xffff);
|
|
|
|
mbuf_up->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
|
|
mbuf_up->m_pkthdr.csum_flags |= CSUM_IP_VALID;
|
|
mbuf_up->m_pkthdr.csum_flags |=
|
|
(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
|
|
|
|
} else {
|
|
|
|
if (ext_info.vlan) {
|
|
mbuf_up->m_pkthdr.ether_vtag = ext_info.vlan;
|
|
mbuf_up->m_flags |= M_VLANTAG;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_rx_term During unload terminate and free all descriptors
|
|
* @vpath_handle Rx vpath Handle @rxdh Rx Descriptor Handle @state Descriptor
|
|
* State @userdata Per-adapter Data @reopen vpath open/reopen option
|
|
*/
|
|
/* ARGSUSED */
|
|
void
|
|
vxge_rx_term(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
|
|
void *dtr_priv, vxge_hal_rxd_state_e state, void *userdata,
|
|
vxge_hal_reopen_e reopen)
|
|
{
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
|
|
vxge_rxd_priv_t *rxd_priv = (vxge_rxd_priv_t *) dtr_priv;
|
|
|
|
if (state != VXGE_HAL_RXD_STATE_POSTED)
|
|
return;
|
|
|
|
if (rxd_priv != NULL) {
|
|
bus_dmamap_sync(vpath->dma_tag_rx, rxd_priv->dma_map,
|
|
BUS_DMASYNC_POSTREAD);
|
|
bus_dmamap_unload(vpath->dma_tag_rx, rxd_priv->dma_map);
|
|
bus_dmamap_destroy(vpath->dma_tag_rx, rxd_priv->dma_map);
|
|
|
|
vxge_free_packet(rxd_priv->mbuf_pkt);
|
|
}
|
|
/* Free the descriptor */
|
|
vxge_hal_ring_rxd_free(vpath_handle, rxdh);
|
|
}
|
|
|
|
/*
|
|
* vxge_rx_rxd_1b_get
|
|
* Get descriptors of packet to send up
|
|
*/
|
|
void
|
|
vxge_rx_rxd_1b_get(vxge_vpath_t *vpath, vxge_hal_rxd_h rxdh, void *dtr_priv)
|
|
{
|
|
vxge_rxd_priv_t *rxd_priv = (vxge_rxd_priv_t *) dtr_priv;
|
|
mbuf_t mbuf_up = rxd_priv->mbuf_pkt;
|
|
|
|
/* Retrieve data from completed descriptor */
|
|
vxge_hal_ring_rxd_1b_get(vpath->handle, rxdh, &rxd_priv->dma_addr[0],
|
|
(u32 *) &rxd_priv->dma_sizes[0]);
|
|
|
|
/* Update newly created buffer to be sent up with packet length */
|
|
mbuf_up->m_len = rxd_priv->dma_sizes[0];
|
|
mbuf_up->m_pkthdr.len = rxd_priv->dma_sizes[0];
|
|
mbuf_up->m_next = NULL;
|
|
}
|
|
|
|
/*
|
|
* vxge_rx_rxd_1b_set
|
|
* Allocates new mbufs to be placed into descriptors
|
|
*/
|
|
int
|
|
vxge_rx_rxd_1b_set(vxge_vpath_t *vpath, vxge_hal_rxd_h rxdh, void *dtr_priv)
|
|
{
|
|
int num_segs, err = 0;
|
|
|
|
mbuf_t mbuf_pkt;
|
|
bus_dmamap_t dma_map;
|
|
bus_dma_segment_t dma_buffers[1];
|
|
vxge_rxd_priv_t *rxd_priv = (vxge_rxd_priv_t *) dtr_priv;
|
|
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
mbuf_pkt = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, vdev->rx_mbuf_sz);
|
|
if (!mbuf_pkt) {
|
|
err = ENOBUFS;
|
|
VXGE_DRV_STATS(vpath, rx_no_buf);
|
|
device_printf(vdev->ndev, "out of memory to allocate mbuf\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
/* Update mbuf's length, packet length and receive interface */
|
|
mbuf_pkt->m_len = vdev->rx_mbuf_sz;
|
|
mbuf_pkt->m_pkthdr.len = vdev->rx_mbuf_sz;
|
|
mbuf_pkt->m_pkthdr.rcvif = vdev->ifp;
|
|
|
|
/* Load DMA map */
|
|
err = vxge_dma_mbuf_coalesce(vpath->dma_tag_rx, vpath->extra_dma_map,
|
|
&mbuf_pkt, dma_buffers, &num_segs);
|
|
if (err != 0) {
|
|
VXGE_DRV_STATS(vpath, rx_map_fail);
|
|
vxge_free_packet(mbuf_pkt);
|
|
goto _exit0;
|
|
}
|
|
|
|
/* Unload DMA map of mbuf in current descriptor */
|
|
bus_dmamap_sync(vpath->dma_tag_rx, rxd_priv->dma_map,
|
|
BUS_DMASYNC_POSTREAD);
|
|
bus_dmamap_unload(vpath->dma_tag_rx, rxd_priv->dma_map);
|
|
|
|
/* Update descriptor private data */
|
|
dma_map = rxd_priv->dma_map;
|
|
rxd_priv->mbuf_pkt = mbuf_pkt;
|
|
rxd_priv->dma_addr[0] = htole64(dma_buffers->ds_addr);
|
|
rxd_priv->dma_map = vpath->extra_dma_map;
|
|
vpath->extra_dma_map = dma_map;
|
|
|
|
/* Pre-Read/Write sync */
|
|
bus_dmamap_sync(vpath->dma_tag_rx, rxd_priv->dma_map,
|
|
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
|
|
|
/* Set descriptor buffer */
|
|
vxge_hal_ring_rxd_1b_set(rxdh, rxd_priv->dma_addr[0], vdev->rx_mbuf_sz);
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_link_up
|
|
* Callback for Link-up indication from HAL
|
|
*/
|
|
/* ARGSUSED */
|
|
void
|
|
vxge_link_up(vxge_hal_device_h devh, void *userdata)
|
|
{
|
|
int i;
|
|
vxge_vpath_t *vpath;
|
|
vxge_hal_device_hw_info_t *hw_info;
|
|
|
|
vxge_dev_t *vdev = (vxge_dev_t *) userdata;
|
|
hw_info = &vdev->config.hw_info;
|
|
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
if (vdev->config.intr_mode == VXGE_HAL_INTR_MODE_MSIX) {
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath = &(vdev->vpaths[i]);
|
|
vxge_hal_vpath_tti_ci_set(vpath->handle);
|
|
vxge_hal_vpath_rti_ci_set(vpath->handle);
|
|
}
|
|
}
|
|
|
|
if (vdev->is_privilaged && (hw_info->ports > 1)) {
|
|
vxge_active_port_update(vdev);
|
|
device_printf(vdev->ndev,
|
|
"Active Port : %lld\n", vdev->active_port);
|
|
}
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
if_link_state_change(ifp, LINK_STATE_UP);
|
|
}
|
|
|
|
/*
|
|
* vxge_link_down
|
|
* Callback for Link-down indication from HAL
|
|
*/
|
|
/* ARGSUSED */
|
|
void
|
|
vxge_link_down(vxge_hal_device_h devh, void *userdata)
|
|
{
|
|
int i;
|
|
vxge_vpath_t *vpath;
|
|
vxge_dev_t *vdev = (vxge_dev_t *) userdata;
|
|
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
if (vdev->config.intr_mode == VXGE_HAL_INTR_MODE_MSIX) {
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath = &(vdev->vpaths[i]);
|
|
vxge_hal_vpath_tti_ci_reset(vpath->handle);
|
|
vxge_hal_vpath_rti_ci_reset(vpath->handle);
|
|
}
|
|
}
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
if_link_state_change(ifp, LINK_STATE_DOWN);
|
|
}
|
|
|
|
/*
|
|
* vxge_reset
|
|
*/
|
|
void
|
|
vxge_reset(vxge_dev_t *vdev)
|
|
{
|
|
if (!vdev->is_initialized)
|
|
return;
|
|
|
|
VXGE_DRV_LOCK(vdev);
|
|
vxge_stop_locked(vdev);
|
|
vxge_init_locked(vdev);
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
}
|
|
|
|
/*
|
|
* vxge_crit_error
|
|
* Callback for Critical error indication from HAL
|
|
*/
|
|
/* ARGSUSED */
|
|
void
|
|
vxge_crit_error(vxge_hal_device_h devh, void *userdata,
|
|
vxge_hal_event_e type, u64 serr_data)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) userdata;
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
switch (type) {
|
|
case VXGE_HAL_EVENT_SERR:
|
|
case VXGE_HAL_EVENT_KDFCCTL:
|
|
case VXGE_HAL_EVENT_CRITICAL:
|
|
vxge_hal_device_intr_disable(vdev->devh);
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
if_link_state_change(ifp, LINK_STATE_DOWN);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_ifp_setup
|
|
*/
|
|
int
|
|
vxge_ifp_setup(device_t ndev)
|
|
{
|
|
ifnet_t ifp;
|
|
int i, j, err = 0;
|
|
|
|
vxge_dev_t *vdev = (vxge_dev_t *) device_get_softc(ndev);
|
|
|
|
for (i = 0, j = 0; i < VXGE_HAL_MAX_VIRTUAL_PATHS; i++) {
|
|
if (!bVAL1(vdev->config.hw_info.vpath_mask, i))
|
|
continue;
|
|
|
|
if (j >= vdev->no_of_vpath)
|
|
break;
|
|
|
|
vdev->vpaths[j].vp_id = i;
|
|
vdev->vpaths[j].vp_index = j;
|
|
vdev->vpaths[j].vdev = vdev;
|
|
vdev->vpaths[j].is_configured = TRUE;
|
|
|
|
vxge_os_memcpy((u8 *) vdev->vpaths[j].mac_addr,
|
|
(u8 *) (vdev->config.hw_info.mac_addrs[i]),
|
|
(size_t) ETHER_ADDR_LEN);
|
|
j++;
|
|
}
|
|
|
|
/* Get interface ifnet structure for this Ether device */
|
|
ifp = if_alloc(IFT_ETHER);
|
|
if (ifp == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"memory allocation for ifnet failed\n");
|
|
err = ENXIO;
|
|
goto _exit0;
|
|
}
|
|
vdev->ifp = ifp;
|
|
|
|
/* Initialize interface ifnet structure */
|
|
if_initname(ifp, device_get_name(ndev), device_get_unit(ndev));
|
|
|
|
ifp->if_baudrate = VXGE_BAUDRATE;
|
|
ifp->if_init = vxge_init;
|
|
ifp->if_softc = vdev;
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
|
ifp->if_ioctl = vxge_ioctl;
|
|
ifp->if_start = vxge_send;
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
ifp->if_transmit = vxge_mq_send;
|
|
ifp->if_qflush = vxge_mq_qflush;
|
|
#endif
|
|
ifp->if_snd.ifq_drv_maxlen = max(vdev->config.ifq_maxlen, ifqmaxlen);
|
|
IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
|
|
/* IFQ_SET_READY(&ifp->if_snd); */
|
|
|
|
ifp->if_hdrlen = sizeof(struct ether_vlan_header);
|
|
|
|
ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
|
|
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
|
|
ifp->if_capabilities |= IFCAP_JUMBO_MTU;
|
|
|
|
if (vdev->config.tso_enable)
|
|
vxge_tso_config(vdev);
|
|
|
|
if (vdev->config.lro_enable)
|
|
ifp->if_capabilities |= IFCAP_LRO;
|
|
|
|
ifp->if_capenable = ifp->if_capabilities;
|
|
|
|
strlcpy(vdev->ndev_name, device_get_nameunit(ndev),
|
|
sizeof(vdev->ndev_name));
|
|
|
|
/* Attach the interface */
|
|
ether_ifattach(ifp, vdev->vpaths[0].mac_addr);
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_isr_setup
|
|
* Register isr functions
|
|
*/
|
|
int
|
|
vxge_isr_setup(vxge_dev_t *vdev)
|
|
{
|
|
int i, irq_rid, err = 0;
|
|
vxge_vpath_t *vpath;
|
|
|
|
void *isr_func_arg;
|
|
void (*isr_func_ptr) (void *);
|
|
|
|
switch (vdev->config.intr_mode) {
|
|
case VXGE_HAL_INTR_MODE_IRQLINE:
|
|
err = bus_setup_intr(vdev->ndev,
|
|
vdev->config.isr_info[0].irq_res,
|
|
(INTR_TYPE_NET | INTR_MPSAFE),
|
|
vxge_isr_filter, vxge_isr_line, vdev,
|
|
&vdev->config.isr_info[0].irq_handle);
|
|
break;
|
|
|
|
case VXGE_HAL_INTR_MODE_MSIX:
|
|
for (i = 0; i < vdev->intr_count; i++) {
|
|
|
|
irq_rid = vdev->config.isr_info[i].irq_rid;
|
|
vpath = &vdev->vpaths[irq_rid / 4];
|
|
|
|
if ((irq_rid % 4) == 2) {
|
|
isr_func_ptr = vxge_isr_msix;
|
|
isr_func_arg = (void *) vpath;
|
|
} else if ((irq_rid % 4) == 3) {
|
|
isr_func_ptr = vxge_isr_msix_alarm;
|
|
isr_func_arg = (void *) vpath;
|
|
} else
|
|
break;
|
|
|
|
err = bus_setup_intr(vdev->ndev,
|
|
vdev->config.isr_info[i].irq_res,
|
|
(INTR_TYPE_NET | INTR_MPSAFE), NULL,
|
|
(void *) isr_func_ptr, (void *) isr_func_arg,
|
|
&vdev->config.isr_info[i].irq_handle);
|
|
if (err != 0)
|
|
break;
|
|
}
|
|
|
|
if (err != 0) {
|
|
/* Teardown interrupt handler */
|
|
while (--i > 0)
|
|
bus_teardown_intr(vdev->ndev,
|
|
vdev->config.isr_info[i].irq_res,
|
|
vdev->config.isr_info[i].irq_handle);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_isr_filter
|
|
* ISR filter function - filter interrupts from other shared devices
|
|
*/
|
|
int
|
|
vxge_isr_filter(void *handle)
|
|
{
|
|
u64 val64 = 0;
|
|
vxge_dev_t *vdev = (vxge_dev_t *) handle;
|
|
__hal_device_t *hldev = (__hal_device_t *) vdev->devh;
|
|
|
|
vxge_hal_common_reg_t *common_reg =
|
|
(vxge_hal_common_reg_t *) (hldev->common_reg);
|
|
|
|
val64 = vxge_os_pio_mem_read64(vdev->pdev, (vdev->devh)->regh0,
|
|
&common_reg->titan_general_int_status);
|
|
|
|
return ((val64) ? FILTER_SCHEDULE_THREAD : FILTER_STRAY);
|
|
}
|
|
|
|
/*
|
|
* vxge_isr_line
|
|
* Interrupt service routine for Line interrupts
|
|
*/
|
|
void
|
|
vxge_isr_line(void *vdev_ptr)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) vdev_ptr;
|
|
|
|
vxge_hal_device_handle_irq(vdev->devh, 0);
|
|
}
|
|
|
|
void
|
|
vxge_isr_msix(void *vpath_ptr)
|
|
{
|
|
u32 got_rx = 0;
|
|
u32 got_tx = 0;
|
|
|
|
__hal_virtualpath_t *hal_vpath;
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) vpath_ptr;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
hal_vpath = ((__hal_vpath_handle_t *) vpath->handle)->vpath;
|
|
|
|
VXGE_DRV_STATS(vpath, isr_msix);
|
|
VXGE_HAL_DEVICE_STATS_SW_INFO_TRAFFIC_INTR(vdev->devh);
|
|
|
|
vxge_hal_vpath_mf_msix_mask(vpath->handle, vpath->msix_vec);
|
|
|
|
/* processing rx */
|
|
vxge_hal_vpath_poll_rx(vpath->handle, &got_rx);
|
|
|
|
/* processing tx */
|
|
if (hal_vpath->vp_config->fifo.enable) {
|
|
vxge_intr_coalesce_tx(vpath);
|
|
vxge_hal_vpath_poll_tx(vpath->handle, &got_tx);
|
|
}
|
|
|
|
vxge_hal_vpath_mf_msix_unmask(vpath->handle, vpath->msix_vec);
|
|
}
|
|
|
|
void
|
|
vxge_isr_msix_alarm(void *vpath_ptr)
|
|
{
|
|
int i;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
vxge_vpath_t *vpath = (vxge_vpath_t *) vpath_ptr;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
|
|
VXGE_HAL_DEVICE_STATS_SW_INFO_NOT_TRAFFIC_INTR(vdev->devh);
|
|
|
|
/* Process alarms in each vpath */
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
|
|
vpath = &(vdev->vpaths[i]);
|
|
vxge_hal_vpath_mf_msix_mask(vpath->handle,
|
|
vpath->msix_vec_alarm);
|
|
status = vxge_hal_vpath_alarm_process(vpath->handle, 0);
|
|
if ((status == VXGE_HAL_ERR_EVENT_SLOT_FREEZE) ||
|
|
(status == VXGE_HAL_ERR_EVENT_SERR)) {
|
|
device_printf(vdev->ndev,
|
|
"processing alarms urecoverable error %x\n",
|
|
status);
|
|
|
|
/* Stop the driver */
|
|
vdev->is_initialized = FALSE;
|
|
break;
|
|
}
|
|
vxge_hal_vpath_mf_msix_unmask(vpath->handle,
|
|
vpath->msix_vec_alarm);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_msix_enable
|
|
*/
|
|
vxge_hal_status_e
|
|
vxge_msix_enable(vxge_dev_t *vdev)
|
|
{
|
|
int i, first_vp_id, msix_id;
|
|
|
|
vxge_vpath_t *vpath;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
/*
|
|
* Unmasking and Setting MSIX vectors before enabling interrupts
|
|
* tim[] : 0 - Tx ## 1 - Rx ## 2 - UMQ-DMQ ## 0 - BITMAP
|
|
*/
|
|
int tim[4] = {0, 1, 0, 0};
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
|
|
vpath = vdev->vpaths + i;
|
|
first_vp_id = vdev->vpaths[0].vp_id;
|
|
|
|
msix_id = vpath->vp_id * VXGE_HAL_VPATH_MSIX_ACTIVE;
|
|
tim[1] = vpath->msix_vec = msix_id + 1;
|
|
|
|
vpath->msix_vec_alarm = first_vp_id *
|
|
VXGE_HAL_VPATH_MSIX_ACTIVE + VXGE_HAL_VPATH_MSIX_ALARM_ID;
|
|
|
|
status = vxge_hal_vpath_mf_msix_set(vpath->handle,
|
|
tim, VXGE_HAL_VPATH_MSIX_ALARM_ID);
|
|
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"failed to set msix vectors to vpath\n");
|
|
break;
|
|
}
|
|
|
|
vxge_hal_vpath_mf_msix_unmask(vpath->handle, vpath->msix_vec);
|
|
vxge_hal_vpath_mf_msix_unmask(vpath->handle,
|
|
vpath->msix_vec_alarm);
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* vxge_media_init
|
|
* Initializes, adds and sets media
|
|
*/
|
|
void
|
|
vxge_media_init(vxge_dev_t *vdev)
|
|
{
|
|
ifmedia_init(&vdev->media,
|
|
IFM_IMASK, vxge_media_change, vxge_media_status);
|
|
|
|
/* Add supported media */
|
|
ifmedia_add(&vdev->media,
|
|
IFM_ETHER | vdev->ifm_optics | IFM_FDX,
|
|
0, NULL);
|
|
|
|
/* Set media */
|
|
ifmedia_add(&vdev->media, IFM_ETHER | IFM_AUTO, 0, NULL);
|
|
ifmedia_set(&vdev->media, IFM_ETHER | IFM_AUTO);
|
|
}
|
|
|
|
/*
|
|
* vxge_media_status
|
|
* Callback for interface media settings
|
|
*/
|
|
void
|
|
vxge_media_status(ifnet_t ifp, struct ifmediareq *ifmr)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
vxge_hal_device_t *hldev = vdev->devh;
|
|
|
|
ifmr->ifm_status = IFM_AVALID;
|
|
ifmr->ifm_active = IFM_ETHER;
|
|
|
|
/* set link state */
|
|
if (vxge_hal_device_link_state_get(hldev) == VXGE_HAL_LINK_UP) {
|
|
ifmr->ifm_status |= IFM_ACTIVE;
|
|
ifmr->ifm_active |= vdev->ifm_optics | IFM_FDX;
|
|
if_link_state_change(ifp, LINK_STATE_UP);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_media_change
|
|
* Media change driver callback
|
|
*/
|
|
int
|
|
vxge_media_change(ifnet_t ifp)
|
|
{
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
struct ifmedia *ifmediap = &vdev->media;
|
|
|
|
return (IFM_TYPE(ifmediap->ifm_media) != IFM_ETHER ? EINVAL : 0);
|
|
}
|
|
|
|
/*
|
|
* Allocate PCI resources
|
|
*/
|
|
int
|
|
vxge_alloc_resources(vxge_dev_t *vdev)
|
|
{
|
|
int err = 0;
|
|
vxge_pci_info_t *pci_info = NULL;
|
|
vxge_free_resources_e error_level = VXGE_FREE_NONE;
|
|
|
|
device_t ndev = vdev->ndev;
|
|
|
|
/* Allocate Buffer for HAL Device Configuration */
|
|
vdev->device_config = (vxge_hal_device_config_t *)
|
|
vxge_mem_alloc(sizeof(vxge_hal_device_config_t));
|
|
|
|
if (!vdev->device_config) {
|
|
err = ENOMEM;
|
|
error_level = VXGE_DISABLE_PCI_BUSMASTER;
|
|
device_printf(vdev->ndev,
|
|
"failed to allocate memory for device config\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
|
|
pci_info = (vxge_pci_info_t *) vxge_mem_alloc(sizeof(vxge_pci_info_t));
|
|
if (!pci_info) {
|
|
error_level = VXGE_FREE_DEVICE_CONFIG;
|
|
err = ENOMEM;
|
|
device_printf(vdev->ndev,
|
|
"failed to allocate memory for pci info\n");
|
|
goto _exit0;
|
|
}
|
|
pci_info->ndev = ndev;
|
|
vdev->pdev = pci_info;
|
|
|
|
err = vxge_alloc_bar_resources(vdev, 0);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_BAR0;
|
|
goto _exit0;
|
|
}
|
|
|
|
err = vxge_alloc_bar_resources(vdev, 1);
|
|
if (err != 0) {
|
|
error_level = VXGE_FREE_BAR1;
|
|
goto _exit0;
|
|
}
|
|
|
|
err = vxge_alloc_bar_resources(vdev, 2);
|
|
if (err != 0)
|
|
error_level = VXGE_FREE_BAR2;
|
|
|
|
_exit0:
|
|
if (error_level)
|
|
vxge_free_resources(ndev, error_level);
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_alloc_bar_resources
|
|
* Allocates BAR resources
|
|
*/
|
|
int
|
|
vxge_alloc_bar_resources(vxge_dev_t *vdev, int i)
|
|
{
|
|
int err = 0;
|
|
int res_id = 0;
|
|
vxge_pci_info_t *pci_info = vdev->pdev;
|
|
|
|
res_id = PCIR_BAR((i == 0) ? 0 : (i * 2));
|
|
|
|
pci_info->bar_info[i] =
|
|
bus_alloc_resource_any(vdev->ndev,
|
|
SYS_RES_MEMORY, &res_id, RF_ACTIVE);
|
|
|
|
if (pci_info->bar_info[i] == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"failed to allocate memory for bus resources\n");
|
|
err = ENOMEM;
|
|
goto _exit0;
|
|
}
|
|
|
|
pci_info->reg_map[i] =
|
|
(vxge_bus_res_t *) vxge_mem_alloc(sizeof(vxge_bus_res_t));
|
|
|
|
if (pci_info->reg_map[i] == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"failed to allocate memory bar resources\n");
|
|
err = ENOMEM;
|
|
goto _exit0;
|
|
}
|
|
|
|
((vxge_bus_res_t *) (pci_info->reg_map[i]))->bus_space_tag =
|
|
rman_get_bustag(pci_info->bar_info[i]);
|
|
|
|
((vxge_bus_res_t *) (pci_info->reg_map[i]))->bus_space_handle =
|
|
rman_get_bushandle(pci_info->bar_info[i]);
|
|
|
|
((vxge_bus_res_t *) (pci_info->reg_map[i]))->bar_start_addr =
|
|
pci_info->bar_info[i];
|
|
|
|
((vxge_bus_res_t *) (pci_info->reg_map[i]))->bus_res_len =
|
|
rman_get_size(pci_info->bar_info[i]);
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_alloc_isr_resources
|
|
*/
|
|
int
|
|
vxge_alloc_isr_resources(vxge_dev_t *vdev)
|
|
{
|
|
int i, err = 0, irq_rid;
|
|
int msix_vec_reqd, intr_count, msix_count;
|
|
|
|
int intr_mode = VXGE_HAL_INTR_MODE_IRQLINE;
|
|
|
|
if (vdev->config.intr_mode == VXGE_HAL_INTR_MODE_MSIX) {
|
|
/* MSI-X messages supported by device */
|
|
intr_count = pci_msix_count(vdev->ndev);
|
|
if (intr_count) {
|
|
|
|
msix_vec_reqd = 4 * vdev->no_of_vpath;
|
|
if (intr_count >= msix_vec_reqd) {
|
|
intr_count = msix_vec_reqd;
|
|
|
|
err = pci_alloc_msix(vdev->ndev, &intr_count);
|
|
if (err == 0)
|
|
intr_mode = VXGE_HAL_INTR_MODE_MSIX;
|
|
}
|
|
|
|
if ((err != 0) || (intr_count < msix_vec_reqd)) {
|
|
device_printf(vdev->ndev, "Unable to allocate "
|
|
"msi/x vectors switching to INTA mode\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
err = 0;
|
|
vdev->intr_count = 0;
|
|
vdev->config.intr_mode = intr_mode;
|
|
|
|
switch (vdev->config.intr_mode) {
|
|
case VXGE_HAL_INTR_MODE_IRQLINE:
|
|
vdev->config.isr_info[0].irq_rid = 0;
|
|
vdev->config.isr_info[0].irq_res =
|
|
bus_alloc_resource_any(vdev->ndev, SYS_RES_IRQ,
|
|
&vdev->config.isr_info[0].irq_rid,
|
|
(RF_SHAREABLE | RF_ACTIVE));
|
|
|
|
if (vdev->config.isr_info[0].irq_res == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"failed to allocate line interrupt resource\n");
|
|
err = ENOMEM;
|
|
goto _exit0;
|
|
}
|
|
vdev->intr_count++;
|
|
break;
|
|
|
|
case VXGE_HAL_INTR_MODE_MSIX:
|
|
msix_count = 0;
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
irq_rid = i * 4;
|
|
|
|
vdev->config.isr_info[msix_count].irq_rid = irq_rid + 2;
|
|
vdev->config.isr_info[msix_count].irq_res =
|
|
bus_alloc_resource_any(vdev->ndev, SYS_RES_IRQ,
|
|
&vdev->config.isr_info[msix_count].irq_rid,
|
|
(RF_SHAREABLE | RF_ACTIVE));
|
|
|
|
if (vdev->config.isr_info[msix_count].irq_res == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"allocating bus resource (rid %d) failed\n",
|
|
vdev->config.isr_info[msix_count].irq_rid);
|
|
err = ENOMEM;
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->intr_count++;
|
|
err = bus_bind_intr(vdev->ndev,
|
|
vdev->config.isr_info[msix_count].irq_res,
|
|
(i % mp_ncpus));
|
|
if (err != 0)
|
|
break;
|
|
|
|
msix_count++;
|
|
}
|
|
|
|
vdev->config.isr_info[msix_count].irq_rid = 3;
|
|
vdev->config.isr_info[msix_count].irq_res =
|
|
bus_alloc_resource_any(vdev->ndev, SYS_RES_IRQ,
|
|
&vdev->config.isr_info[msix_count].irq_rid,
|
|
(RF_SHAREABLE | RF_ACTIVE));
|
|
|
|
if (vdev->config.isr_info[msix_count].irq_res == NULL) {
|
|
device_printf(vdev->ndev,
|
|
"allocating bus resource (rid %d) failed\n",
|
|
vdev->config.isr_info[msix_count].irq_rid);
|
|
err = ENOMEM;
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->intr_count++;
|
|
err = bus_bind_intr(vdev->ndev,
|
|
vdev->config.isr_info[msix_count].irq_res, (i % mp_ncpus));
|
|
|
|
break;
|
|
}
|
|
|
|
vdev->device_config->intr_mode = vdev->config.intr_mode;
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_free_resources
|
|
* Undo what-all we did during load/attach
|
|
*/
|
|
void
|
|
vxge_free_resources(device_t ndev, vxge_free_resources_e vxge_free_resource)
|
|
{
|
|
int i;
|
|
vxge_dev_t *vdev;
|
|
|
|
vdev = (vxge_dev_t *) device_get_softc(ndev);
|
|
|
|
switch (vxge_free_resource) {
|
|
case VXGE_FREE_ALL:
|
|
for (i = 0; i < vdev->intr_count; i++) {
|
|
bus_teardown_intr(ndev,
|
|
vdev->config.isr_info[i].irq_res,
|
|
vdev->config.isr_info[i].irq_handle);
|
|
}
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_INTERFACE:
|
|
ether_ifdetach(vdev->ifp);
|
|
bus_generic_detach(ndev);
|
|
if_free(vdev->ifp);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_MEDIA:
|
|
ifmedia_removeall(&vdev->media);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_MUTEX:
|
|
vxge_mutex_destroy(vdev);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_VPATH:
|
|
vxge_mem_free(vdev->vpaths,
|
|
vdev->no_of_vpath * sizeof(vxge_vpath_t));
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_TERMINATE_DEVICE:
|
|
if (vdev->devh != NULL) {
|
|
vxge_hal_device_private_set(vdev->devh, 0);
|
|
vxge_hal_device_terminate(vdev->devh);
|
|
}
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_ISR_RESOURCE:
|
|
vxge_free_isr_resources(vdev);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_BAR2:
|
|
vxge_free_bar_resources(vdev, 2);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_BAR1:
|
|
vxge_free_bar_resources(vdev, 1);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_BAR0:
|
|
vxge_free_bar_resources(vdev, 0);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_PCI_INFO:
|
|
vxge_mem_free(vdev->pdev, sizeof(vxge_pci_info_t));
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_DEVICE_CONFIG:
|
|
vxge_mem_free(vdev->device_config,
|
|
sizeof(vxge_hal_device_config_t));
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_DISABLE_PCI_BUSMASTER:
|
|
pci_disable_busmaster(ndev);
|
|
/* FALLTHROUGH */
|
|
|
|
case VXGE_FREE_TERMINATE_DRIVER:
|
|
if (vxge_dev_ref_count) {
|
|
--vxge_dev_ref_count;
|
|
if (0 == vxge_dev_ref_count)
|
|
vxge_hal_driver_terminate();
|
|
}
|
|
/* FALLTHROUGH */
|
|
|
|
default:
|
|
case VXGE_FREE_NONE:
|
|
break;
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
void
|
|
vxge_free_isr_resources(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
|
|
switch (vdev->config.intr_mode) {
|
|
case VXGE_HAL_INTR_MODE_IRQLINE:
|
|
if (vdev->config.isr_info[0].irq_res) {
|
|
bus_release_resource(vdev->ndev, SYS_RES_IRQ,
|
|
vdev->config.isr_info[0].irq_rid,
|
|
vdev->config.isr_info[0].irq_res);
|
|
|
|
vdev->config.isr_info[0].irq_res = NULL;
|
|
}
|
|
break;
|
|
|
|
case VXGE_HAL_INTR_MODE_MSIX:
|
|
for (i = 0; i < vdev->intr_count; i++) {
|
|
if (vdev->config.isr_info[i].irq_res) {
|
|
bus_release_resource(vdev->ndev, SYS_RES_IRQ,
|
|
vdev->config.isr_info[i].irq_rid,
|
|
vdev->config.isr_info[i].irq_res);
|
|
|
|
vdev->config.isr_info[i].irq_res = NULL;
|
|
}
|
|
}
|
|
|
|
if (vdev->intr_count)
|
|
pci_release_msi(vdev->ndev);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
vxge_free_bar_resources(vxge_dev_t *vdev, int i)
|
|
{
|
|
int res_id = 0;
|
|
vxge_pci_info_t *pci_info = vdev->pdev;
|
|
|
|
res_id = PCIR_BAR((i == 0) ? 0 : (i * 2));
|
|
|
|
if (pci_info->bar_info[i])
|
|
bus_release_resource(vdev->ndev, SYS_RES_MEMORY,
|
|
res_id, pci_info->bar_info[i]);
|
|
|
|
vxge_mem_free(pci_info->reg_map[i], sizeof(vxge_bus_res_t));
|
|
}
|
|
|
|
/*
|
|
* vxge_init_mutex
|
|
* Initializes mutexes used in driver
|
|
*/
|
|
void
|
|
vxge_mutex_init(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
|
|
snprintf(vdev->mtx_drv_name, sizeof(vdev->mtx_drv_name),
|
|
"%s_drv", vdev->ndev_name);
|
|
|
|
mtx_init(&vdev->mtx_drv, vdev->mtx_drv_name,
|
|
MTX_NETWORK_LOCK, MTX_DEF);
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
snprintf(vdev->vpaths[i].mtx_tx_name,
|
|
sizeof(vdev->vpaths[i].mtx_tx_name), "%s_tx_%d",
|
|
vdev->ndev_name, i);
|
|
|
|
mtx_init(&vdev->vpaths[i].mtx_tx,
|
|
vdev->vpaths[i].mtx_tx_name, NULL, MTX_DEF);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_mutex_destroy
|
|
* Destroys mutexes used in driver
|
|
*/
|
|
void
|
|
vxge_mutex_destroy(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++)
|
|
VXGE_TX_LOCK_DESTROY(&(vdev->vpaths[i]));
|
|
|
|
VXGE_DRV_LOCK_DESTROY(vdev);
|
|
}
|
|
|
|
/*
|
|
* vxge_rth_config
|
|
*/
|
|
vxge_hal_status_e
|
|
vxge_rth_config(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
vxge_hal_vpath_h vpath_handle;
|
|
vxge_hal_rth_hash_types_t hash_types;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
u8 mtable[256] = {0};
|
|
|
|
/* Filling matable with bucket-to-vpath mapping */
|
|
vdev->config.rth_bkt_sz = VXGE_DEFAULT_RTH_BUCKET_SIZE;
|
|
|
|
for (i = 0; i < (1 << vdev->config.rth_bkt_sz); i++)
|
|
mtable[i] = i % vdev->no_of_vpath;
|
|
|
|
/* Fill RTH hash types */
|
|
hash_types.hash_type_tcpipv4_en = VXGE_HAL_RING_HASH_TYPE_TCP_IPV4;
|
|
hash_types.hash_type_tcpipv6_en = VXGE_HAL_RING_HASH_TYPE_TCP_IPV6;
|
|
hash_types.hash_type_tcpipv6ex_en = VXGE_HAL_RING_HASH_TYPE_TCP_IPV6_EX;
|
|
hash_types.hash_type_ipv4_en = VXGE_HAL_RING_HASH_TYPE_IPV4;
|
|
hash_types.hash_type_ipv6_en = VXGE_HAL_RING_HASH_TYPE_IPV6;
|
|
hash_types.hash_type_ipv6ex_en = VXGE_HAL_RING_HASH_TYPE_IPV6_EX;
|
|
|
|
/* set indirection table, bucket-to-vpath mapping */
|
|
status = vxge_hal_vpath_rts_rth_itable_set(vdev->vpath_handles,
|
|
vdev->no_of_vpath, mtable,
|
|
((u32) (1 << vdev->config.rth_bkt_sz)));
|
|
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev, "rth configuration failed\n");
|
|
goto _exit0;
|
|
}
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
status = vxge_hal_vpath_rts_rth_set(vpath_handle,
|
|
RTH_ALG_JENKINS,
|
|
&hash_types, vdev->config.rth_bkt_sz, TRUE);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"rth configuration failed for vpath (%d)\n",
|
|
vdev->vpaths[i].vp_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_exit0:
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* vxge_vpath_config
|
|
* Sets HAL parameter values from kenv
|
|
*/
|
|
void
|
|
vxge_vpath_config(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
u32 no_of_vpath = 0;
|
|
vxge_hal_vp_config_t *vp_config;
|
|
vxge_hal_device_config_t *device_config = vdev->device_config;
|
|
|
|
device_config->debug_level = VXGE_TRACE;
|
|
device_config->debug_mask = VXGE_COMPONENT_ALL;
|
|
device_config->device_poll_millis = VXGE_DEFAULT_DEVICE_POLL_MILLIS;
|
|
|
|
vdev->config.no_of_vpath =
|
|
min(vdev->config.no_of_vpath, vdev->max_supported_vpath);
|
|
|
|
for (i = 0; i < VXGE_HAL_MAX_VIRTUAL_PATHS; i++) {
|
|
vp_config = &(device_config->vp_config[i]);
|
|
vp_config->fifo.enable = VXGE_HAL_FIFO_DISABLE;
|
|
vp_config->ring.enable = VXGE_HAL_RING_DISABLE;
|
|
}
|
|
|
|
for (i = 0; i < VXGE_HAL_MAX_VIRTUAL_PATHS; i++) {
|
|
if (no_of_vpath >= vdev->config.no_of_vpath)
|
|
break;
|
|
|
|
if (!bVAL1(vdev->config.hw_info.vpath_mask, i))
|
|
continue;
|
|
|
|
no_of_vpath++;
|
|
vp_config = &(device_config->vp_config[i]);
|
|
vp_config->mtu = VXGE_HAL_DEFAULT_MTU;
|
|
vp_config->ring.enable = VXGE_HAL_RING_ENABLE;
|
|
vp_config->ring.post_mode = VXGE_HAL_RING_POST_MODE_DOORBELL;
|
|
vp_config->ring.buffer_mode = VXGE_HAL_RING_RXD_BUFFER_MODE_1;
|
|
vp_config->ring.ring_length =
|
|
vxge_ring_length_get(VXGE_HAL_RING_RXD_BUFFER_MODE_1);
|
|
vp_config->ring.scatter_mode = VXGE_HAL_RING_SCATTER_MODE_A;
|
|
vp_config->rpa_all_vid_en = VXGE_DEFAULT_ALL_VID_ENABLE;
|
|
vp_config->rpa_strip_vlan_tag = VXGE_DEFAULT_STRIP_VLAN_TAG;
|
|
vp_config->rpa_ucast_all_addr_en =
|
|
VXGE_HAL_VPATH_RPA_UCAST_ALL_ADDR_DISABLE;
|
|
|
|
vp_config->rti.intr_enable = VXGE_HAL_TIM_INTR_ENABLE;
|
|
vp_config->rti.txfrm_cnt_en = VXGE_HAL_TXFRM_CNT_EN_ENABLE;
|
|
vp_config->rti.util_sel =
|
|
VXGE_HAL_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL;
|
|
|
|
vp_config->rti.uec_a = VXGE_DEFAULT_RTI_RX_UFC_A;
|
|
vp_config->rti.uec_b = VXGE_DEFAULT_RTI_RX_UFC_B;
|
|
vp_config->rti.uec_c = VXGE_DEFAULT_RTI_RX_UFC_C;
|
|
vp_config->rti.uec_d = VXGE_DEFAULT_RTI_RX_UFC_D;
|
|
|
|
vp_config->rti.urange_a = VXGE_DEFAULT_RTI_RX_URANGE_A;
|
|
vp_config->rti.urange_b = VXGE_DEFAULT_RTI_RX_URANGE_B;
|
|
vp_config->rti.urange_c = VXGE_DEFAULT_RTI_RX_URANGE_C;
|
|
|
|
vp_config->rti.timer_ac_en = VXGE_HAL_TIM_TIMER_AC_ENABLE;
|
|
vp_config->rti.timer_ci_en = VXGE_HAL_TIM_TIMER_CI_ENABLE;
|
|
|
|
vp_config->rti.btimer_val =
|
|
(VXGE_DEFAULT_RTI_BTIMER_VAL * 1000) / 272;
|
|
vp_config->rti.rtimer_val =
|
|
(VXGE_DEFAULT_RTI_RTIMER_VAL * 1000) / 272;
|
|
vp_config->rti.ltimer_val =
|
|
(VXGE_DEFAULT_RTI_LTIMER_VAL * 1000) / 272;
|
|
|
|
if ((no_of_vpath > 1) && (VXGE_DEFAULT_CONFIG_MQ_ENABLE == 0))
|
|
continue;
|
|
|
|
vp_config->fifo.enable = VXGE_HAL_FIFO_ENABLE;
|
|
vp_config->fifo.max_aligned_frags =
|
|
VXGE_DEFAULT_FIFO_ALIGNED_FRAGS;
|
|
|
|
vp_config->tti.intr_enable = VXGE_HAL_TIM_INTR_ENABLE;
|
|
vp_config->tti.txfrm_cnt_en = VXGE_HAL_TXFRM_CNT_EN_ENABLE;
|
|
vp_config->tti.util_sel =
|
|
VXGE_HAL_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL;
|
|
|
|
vp_config->tti.uec_a = VXGE_DEFAULT_TTI_TX_UFC_A;
|
|
vp_config->tti.uec_b = VXGE_DEFAULT_TTI_TX_UFC_B;
|
|
vp_config->tti.uec_c = VXGE_DEFAULT_TTI_TX_UFC_C;
|
|
vp_config->tti.uec_d = VXGE_DEFAULT_TTI_TX_UFC_D;
|
|
|
|
vp_config->tti.urange_a = VXGE_DEFAULT_TTI_TX_URANGE_A;
|
|
vp_config->tti.urange_b = VXGE_DEFAULT_TTI_TX_URANGE_B;
|
|
vp_config->tti.urange_c = VXGE_DEFAULT_TTI_TX_URANGE_C;
|
|
|
|
vp_config->tti.timer_ac_en = VXGE_HAL_TIM_TIMER_AC_ENABLE;
|
|
vp_config->tti.timer_ci_en = VXGE_HAL_TIM_TIMER_CI_ENABLE;
|
|
|
|
vp_config->tti.btimer_val =
|
|
(VXGE_DEFAULT_TTI_BTIMER_VAL * 1000) / 272;
|
|
vp_config->tti.rtimer_val =
|
|
(VXGE_DEFAULT_TTI_RTIMER_VAL * 1000) / 272;
|
|
vp_config->tti.ltimer_val =
|
|
(VXGE_DEFAULT_TTI_LTIMER_VAL * 1000) / 272;
|
|
}
|
|
|
|
vdev->no_of_vpath = no_of_vpath;
|
|
|
|
if (vdev->no_of_vpath == 1)
|
|
vdev->config.tx_steering = 0;
|
|
|
|
if (vdev->config.rth_enable && (vdev->no_of_vpath > 1)) {
|
|
device_config->rth_en = VXGE_HAL_RTH_ENABLE;
|
|
device_config->rth_it_type = VXGE_HAL_RTH_IT_TYPE_MULTI_IT;
|
|
}
|
|
|
|
vdev->config.rth_enable = device_config->rth_en;
|
|
}
|
|
|
|
/*
|
|
* vxge_vpath_cb_fn
|
|
* Virtual path Callback function
|
|
*/
|
|
/* ARGSUSED */
|
|
static vxge_hal_status_e
|
|
vxge_vpath_cb_fn(vxge_hal_client_h client_handle, vxge_hal_up_msg_h msgh,
|
|
vxge_hal_message_type_e msg_type, vxge_hal_obj_id_t obj_id,
|
|
vxge_hal_result_e result, vxge_hal_opaque_handle_t *opaque_handle)
|
|
{
|
|
return (VXGE_HAL_OK);
|
|
}
|
|
|
|
/*
|
|
* vxge_vpath_open
|
|
*/
|
|
int
|
|
vxge_vpath_open(vxge_dev_t *vdev)
|
|
{
|
|
int i, err = EINVAL;
|
|
u64 func_id;
|
|
|
|
vxge_vpath_t *vpath;
|
|
vxge_hal_vpath_attr_t vpath_attr;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
struct lro_ctrl *lro = NULL;
|
|
|
|
bzero(&vpath_attr, sizeof(vxge_hal_vpath_attr_t));
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
|
|
vpath = &(vdev->vpaths[i]);
|
|
lro = &vpath->lro;
|
|
|
|
/* Vpath vpath_attr: FIFO */
|
|
vpath_attr.vp_id = vpath->vp_id;
|
|
vpath_attr.fifo_attr.callback = vxge_tx_compl;
|
|
vpath_attr.fifo_attr.txdl_init = vxge_tx_replenish;
|
|
vpath_attr.fifo_attr.txdl_term = vxge_tx_term;
|
|
vpath_attr.fifo_attr.userdata = vpath;
|
|
vpath_attr.fifo_attr.per_txdl_space = sizeof(vxge_txdl_priv_t);
|
|
|
|
/* Vpath vpath_attr: Ring */
|
|
vpath_attr.ring_attr.callback = vxge_rx_compl;
|
|
vpath_attr.ring_attr.rxd_init = vxge_rx_replenish;
|
|
vpath_attr.ring_attr.rxd_term = vxge_rx_term;
|
|
vpath_attr.ring_attr.userdata = vpath;
|
|
vpath_attr.ring_attr.per_rxd_space = sizeof(vxge_rxd_priv_t);
|
|
|
|
err = vxge_dma_tags_create(vpath);
|
|
if (err != 0) {
|
|
device_printf(vdev->ndev,
|
|
"failed to create dma tags\n");
|
|
break;
|
|
}
|
|
#if __FreeBSD_version >= 800000
|
|
vpath->br = buf_ring_alloc(VXGE_DEFAULT_BR_SIZE, M_DEVBUF,
|
|
M_WAITOK, &vpath->mtx_tx);
|
|
if (vpath->br == NULL) {
|
|
err = ENOMEM;
|
|
break;
|
|
}
|
|
#endif
|
|
status = vxge_hal_vpath_open(vdev->devh, &vpath_attr,
|
|
(vxge_hal_vpath_callback_f) vxge_vpath_cb_fn,
|
|
NULL, &vpath->handle);
|
|
if (status != VXGE_HAL_OK) {
|
|
device_printf(vdev->ndev,
|
|
"failed to open vpath (%d)\n", vpath->vp_id);
|
|
err = EPERM;
|
|
break;
|
|
}
|
|
vpath->is_open = TRUE;
|
|
vdev->vpath_handles[i] = vpath->handle;
|
|
|
|
vpath->tx_ticks = ticks;
|
|
vpath->rx_ticks = ticks;
|
|
|
|
vpath->tti_rtimer_val = VXGE_DEFAULT_TTI_RTIMER_VAL;
|
|
vpath->tti_rtimer_val = VXGE_DEFAULT_TTI_RTIMER_VAL;
|
|
|
|
vpath->tx_intr_coalesce = vdev->config.intr_coalesce;
|
|
vpath->rx_intr_coalesce = vdev->config.intr_coalesce;
|
|
|
|
func_id = vdev->config.hw_info.func_id;
|
|
|
|
if (vdev->config.low_latency &&
|
|
(vdev->config.bw_info[func_id].priority ==
|
|
VXGE_DEFAULT_VPATH_PRIORITY_HIGH)) {
|
|
vpath->tx_intr_coalesce = 0;
|
|
}
|
|
|
|
if (vdev->ifp->if_capenable & IFCAP_LRO) {
|
|
err = tcp_lro_init(lro);
|
|
if (err != 0) {
|
|
device_printf(vdev->ndev,
|
|
"LRO Initialization failed!\n");
|
|
break;
|
|
}
|
|
vpath->lro_enable = TRUE;
|
|
lro->ifp = vdev->ifp;
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
void
|
|
vxge_tso_config(vxge_dev_t *vdev)
|
|
{
|
|
u32 func_id, priority;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
vdev->ifp->if_capabilities |= IFCAP_TSO4;
|
|
|
|
status = vxge_bw_priority_get(vdev, NULL);
|
|
if (status == VXGE_HAL_OK) {
|
|
|
|
func_id = vdev->config.hw_info.func_id;
|
|
priority = vdev->config.bw_info[func_id].priority;
|
|
|
|
if (priority != VXGE_DEFAULT_VPATH_PRIORITY_HIGH)
|
|
vdev->ifp->if_capabilities &= ~IFCAP_TSO4;
|
|
}
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
if (vdev->ifp->if_capabilities & IFCAP_TSO4)
|
|
vdev->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
|
|
#endif
|
|
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_bw_priority_get(vxge_dev_t *vdev, vxge_bw_info_t *bw_info)
|
|
{
|
|
u32 priority, bandwidth;
|
|
u32 vpath_count;
|
|
|
|
u64 func_id, func_mode, vpath_list[VXGE_HAL_MAX_VIRTUAL_PATHS];
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
func_id = vdev->config.hw_info.func_id;
|
|
if (bw_info) {
|
|
func_id = bw_info->func_id;
|
|
func_mode = vdev->config.hw_info.function_mode;
|
|
if ((is_single_func(func_mode)) && (func_id > 0))
|
|
return (VXGE_HAL_FAIL);
|
|
}
|
|
|
|
if (vdev->hw_fw_version >= VXGE_FW_VERSION(1, 8, 0)) {
|
|
|
|
status = vxge_hal_vf_rx_bw_get(vdev->devh,
|
|
func_id, &bandwidth, &priority);
|
|
|
|
} else {
|
|
|
|
status = vxge_hal_get_vpath_list(vdev->devh,
|
|
func_id, vpath_list, &vpath_count);
|
|
|
|
if (status == VXGE_HAL_OK) {
|
|
status = vxge_hal_bw_priority_get(vdev->devh,
|
|
vpath_list[0], &bandwidth, &priority);
|
|
}
|
|
}
|
|
|
|
if (status == VXGE_HAL_OK) {
|
|
if (bw_info) {
|
|
bw_info->priority = priority;
|
|
bw_info->bandwidth = bandwidth;
|
|
} else {
|
|
vdev->config.bw_info[func_id].priority = priority;
|
|
vdev->config.bw_info[func_id].bandwidth = bandwidth;
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* close vpaths
|
|
*/
|
|
void
|
|
vxge_vpath_close(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
vxge_vpath_t *vpath;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
|
|
vpath = &(vdev->vpaths[i]);
|
|
if (vpath->handle)
|
|
vxge_hal_vpath_close(vpath->handle);
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
if (vpath->br != NULL)
|
|
buf_ring_free(vpath->br, M_DEVBUF);
|
|
#endif
|
|
/* Free LRO memory */
|
|
if (vpath->lro_enable)
|
|
tcp_lro_free(&vpath->lro);
|
|
|
|
if (vpath->dma_tag_rx) {
|
|
bus_dmamap_destroy(vpath->dma_tag_rx,
|
|
vpath->extra_dma_map);
|
|
bus_dma_tag_destroy(vpath->dma_tag_rx);
|
|
}
|
|
|
|
if (vpath->dma_tag_tx)
|
|
bus_dma_tag_destroy(vpath->dma_tag_tx);
|
|
|
|
vpath->handle = NULL;
|
|
vpath->is_open = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* reset vpaths
|
|
*/
|
|
void
|
|
vxge_vpath_reset(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
vxge_hal_vpath_h vpath_handle;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
status = vxge_hal_vpath_reset(vpath_handle);
|
|
if (status != VXGE_HAL_OK)
|
|
device_printf(vdev->ndev,
|
|
"failed to reset vpath :%d\n", i);
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
vxge_vpath_get(vxge_dev_t *vdev, mbuf_t mhead)
|
|
{
|
|
struct tcphdr *th = NULL;
|
|
struct udphdr *uh = NULL;
|
|
struct ip *ip = NULL;
|
|
struct ip6_hdr *ip6 = NULL;
|
|
struct ether_vlan_header *eth = NULL;
|
|
void *ulp = NULL;
|
|
|
|
int ehdrlen, iphlen = 0;
|
|
u8 ipproto = 0;
|
|
u16 etype, src_port, dst_port;
|
|
u16 queue_len, counter = 0;
|
|
|
|
src_port = dst_port = 0;
|
|
queue_len = vdev->no_of_vpath;
|
|
|
|
eth = mtod(mhead, struct ether_vlan_header *);
|
|
if (eth->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
|
|
etype = ntohs(eth->evl_proto);
|
|
ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
|
|
} else {
|
|
etype = ntohs(eth->evl_encap_proto);
|
|
ehdrlen = ETHER_HDR_LEN;
|
|
}
|
|
|
|
switch (etype) {
|
|
case ETHERTYPE_IP:
|
|
ip = (struct ip *) (mhead->m_data + ehdrlen);
|
|
iphlen = ip->ip_hl << 2;
|
|
ipproto = ip->ip_p;
|
|
th = (struct tcphdr *) ((caddr_t)ip + iphlen);
|
|
uh = (struct udphdr *) ((caddr_t)ip + iphlen);
|
|
break;
|
|
|
|
case ETHERTYPE_IPV6:
|
|
ip6 = (struct ip6_hdr *) (mhead->m_data + ehdrlen);
|
|
iphlen = sizeof(struct ip6_hdr);
|
|
ipproto = ip6->ip6_nxt;
|
|
|
|
ulp = mtod(mhead, char *) + iphlen;
|
|
th = ((struct tcphdr *) (ulp));
|
|
uh = ((struct udphdr *) (ulp));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (ipproto) {
|
|
case IPPROTO_TCP:
|
|
src_port = th->th_sport;
|
|
dst_port = th->th_dport;
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
src_port = uh->uh_sport;
|
|
dst_port = uh->uh_dport;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
counter = (ntohs(src_port) + ntohs(dst_port)) &
|
|
vpath_selector[queue_len - 1];
|
|
|
|
if (counter >= queue_len)
|
|
counter = queue_len - 1;
|
|
|
|
return (counter);
|
|
}
|
|
|
|
static inline vxge_hal_vpath_h
|
|
vxge_vpath_handle_get(vxge_dev_t *vdev, int i)
|
|
{
|
|
return (vdev->vpaths[i].is_open ? vdev->vpaths[i].handle : NULL);
|
|
}
|
|
|
|
int
|
|
vxge_firmware_verify(vxge_dev_t *vdev)
|
|
{
|
|
int err = 0;
|
|
u64 active_config;
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
if (vdev->fw_upgrade) {
|
|
status = vxge_firmware_upgrade(vdev);
|
|
if (status == VXGE_HAL_OK) {
|
|
err = ENXIO;
|
|
goto _exit0;
|
|
}
|
|
}
|
|
|
|
if ((vdev->config.function_mode != VXGE_DEFAULT_CONFIG_VALUE) &&
|
|
(vdev->config.hw_info.function_mode !=
|
|
(u64) vdev->config.function_mode)) {
|
|
|
|
status = vxge_func_mode_set(vdev);
|
|
if (status == VXGE_HAL_OK)
|
|
err = ENXIO;
|
|
}
|
|
|
|
/* l2_switch configuration */
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_L2SwitchEnabled,
|
|
&active_config);
|
|
|
|
if (status == VXGE_HAL_OK) {
|
|
vdev->l2_switch = active_config;
|
|
if (vdev->config.l2_switch != VXGE_DEFAULT_CONFIG_VALUE) {
|
|
if (vdev->config.l2_switch != active_config) {
|
|
status = vxge_l2switch_mode_set(vdev);
|
|
if (status == VXGE_HAL_OK)
|
|
err = ENXIO;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (vdev->config.hw_info.ports == VXGE_DUAL_PORT_MODE) {
|
|
if (vxge_port_mode_update(vdev) == ENXIO)
|
|
err = ENXIO;
|
|
}
|
|
|
|
_exit0:
|
|
if (err == ENXIO)
|
|
device_printf(vdev->ndev, "PLEASE POWER CYCLE THE SYSTEM\n");
|
|
|
|
return (err);
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_firmware_upgrade(vxge_dev_t *vdev)
|
|
{
|
|
u8 *fw_buffer;
|
|
u32 fw_size;
|
|
vxge_hal_device_hw_info_t *hw_info;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
hw_info = &vdev->config.hw_info;
|
|
|
|
fw_size = sizeof(VXGE_FW_ARRAY_NAME);
|
|
fw_buffer = (u8 *) VXGE_FW_ARRAY_NAME;
|
|
|
|
device_printf(vdev->ndev, "Current firmware version : %s (%s)\n",
|
|
hw_info->fw_version.version, hw_info->fw_date.date);
|
|
|
|
device_printf(vdev->ndev, "Upgrading firmware to %d.%d.%d\n",
|
|
VXGE_MIN_FW_MAJOR_VERSION, VXGE_MIN_FW_MINOR_VERSION,
|
|
VXGE_MIN_FW_BUILD_NUMBER);
|
|
|
|
/* Call HAL API to upgrade firmware */
|
|
status = vxge_hal_mrpcim_fw_upgrade(vdev->pdev,
|
|
(pci_reg_h) vdev->pdev->reg_map[0],
|
|
(u8 *) vdev->pdev->bar_info[0],
|
|
fw_buffer, fw_size);
|
|
|
|
device_printf(vdev->ndev, "firmware upgrade %s\n",
|
|
(status == VXGE_HAL_OK) ? "successful" : "failed");
|
|
|
|
return (status);
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_func_mode_set(vxge_dev_t *vdev)
|
|
{
|
|
u64 active_config;
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
status = vxge_hal_mrpcim_pcie_func_mode_set(vdev->devh,
|
|
vdev->config.function_mode);
|
|
device_printf(vdev->ndev,
|
|
"function mode change %s\n",
|
|
(status == VXGE_HAL_OK) ? "successful" : "failed");
|
|
|
|
if (status == VXGE_HAL_OK) {
|
|
vxge_hal_set_fw_api(vdev->devh, 0ULL,
|
|
VXGE_HAL_API_FUNC_MODE_COMMIT,
|
|
0, 0ULL, 0ULL);
|
|
|
|
vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_NWPortMode,
|
|
&active_config);
|
|
|
|
/*
|
|
* If in MF + DP mode
|
|
* if user changes to SF, change port_mode to single port mode
|
|
*/
|
|
if (((is_multi_func(vdev->config.hw_info.function_mode)) &&
|
|
is_single_func(vdev->config.function_mode)) &&
|
|
(active_config == VXGE_HAL_DP_NP_MODE_DUAL_PORT)) {
|
|
vdev->config.port_mode =
|
|
VXGE_HAL_DP_NP_MODE_SINGLE_PORT;
|
|
|
|
status = vxge_port_mode_set(vdev);
|
|
}
|
|
}
|
|
return (status);
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_port_mode_set(vxge_dev_t *vdev)
|
|
{
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
status = vxge_hal_set_port_mode(vdev->devh, vdev->config.port_mode);
|
|
device_printf(vdev->ndev,
|
|
"port mode change %s\n",
|
|
(status == VXGE_HAL_OK) ? "successful" : "failed");
|
|
|
|
if (status == VXGE_HAL_OK) {
|
|
vxge_hal_set_fw_api(vdev->devh, 0ULL,
|
|
VXGE_HAL_API_FUNC_MODE_COMMIT,
|
|
0, 0ULL, 0ULL);
|
|
|
|
/* Configure vpath_mapping for active-active mode only */
|
|
if (vdev->config.port_mode == VXGE_HAL_DP_NP_MODE_DUAL_PORT) {
|
|
|
|
status = vxge_hal_config_vpath_map(vdev->devh,
|
|
VXGE_DUAL_PORT_MAP);
|
|
|
|
device_printf(vdev->ndev, "dual port map change %s\n",
|
|
(status == VXGE_HAL_OK) ? "successful" : "failed");
|
|
}
|
|
}
|
|
return (status);
|
|
}
|
|
|
|
int
|
|
vxge_port_mode_update(vxge_dev_t *vdev)
|
|
{
|
|
int err = 0;
|
|
u64 active_config;
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
if ((vdev->config.port_mode == VXGE_HAL_DP_NP_MODE_DUAL_PORT) &&
|
|
is_single_func(vdev->config.hw_info.function_mode)) {
|
|
|
|
device_printf(vdev->ndev,
|
|
"Adapter in SF mode, dual port mode is not allowed\n");
|
|
err = EPERM;
|
|
goto _exit0;
|
|
}
|
|
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_NWPortMode,
|
|
&active_config);
|
|
if (status != VXGE_HAL_OK) {
|
|
err = EINVAL;
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->port_mode = active_config;
|
|
if (vdev->config.port_mode != VXGE_DEFAULT_CONFIG_VALUE) {
|
|
if (vdev->config.port_mode != vdev->port_mode) {
|
|
status = vxge_port_mode_set(vdev);
|
|
if (status != VXGE_HAL_OK) {
|
|
err = EINVAL;
|
|
goto _exit0;
|
|
}
|
|
err = ENXIO;
|
|
vdev->port_mode = vdev->config.port_mode;
|
|
}
|
|
}
|
|
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_BehaviourOnFail,
|
|
&active_config);
|
|
if (status != VXGE_HAL_OK) {
|
|
err = EINVAL;
|
|
goto _exit0;
|
|
}
|
|
|
|
vdev->port_failure = active_config;
|
|
|
|
/*
|
|
* active/active mode : set to NoMove
|
|
* active/passive mode: set to Failover-Failback
|
|
*/
|
|
if (vdev->port_mode == VXGE_HAL_DP_NP_MODE_DUAL_PORT)
|
|
vdev->config.port_failure =
|
|
VXGE_HAL_XMAC_NWIF_OnFailure_NoMove;
|
|
|
|
else if (vdev->port_mode == VXGE_HAL_DP_NP_MODE_ACTIVE_PASSIVE)
|
|
vdev->config.port_failure =
|
|
VXGE_HAL_XMAC_NWIF_OnFailure_OtherPortBackOnRestore;
|
|
|
|
if ((vdev->port_mode != VXGE_HAL_DP_NP_MODE_SINGLE_PORT) &&
|
|
(vdev->config.port_failure != vdev->port_failure)) {
|
|
status = vxge_port_behavior_on_failure_set(vdev);
|
|
if (status == VXGE_HAL_OK)
|
|
err = ENXIO;
|
|
}
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_port_mode_get(vxge_dev_t *vdev, vxge_port_info_t *port_info)
|
|
{
|
|
int err = 0;
|
|
u64 active_config;
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_NWPortMode,
|
|
&active_config);
|
|
|
|
if (status != VXGE_HAL_OK) {
|
|
err = ENXIO;
|
|
goto _exit0;
|
|
}
|
|
|
|
port_info->port_mode = active_config;
|
|
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_BehaviourOnFail,
|
|
&active_config);
|
|
if (status != VXGE_HAL_OK) {
|
|
err = ENXIO;
|
|
goto _exit0;
|
|
}
|
|
|
|
port_info->port_failure = active_config;
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_port_behavior_on_failure_set(vxge_dev_t *vdev)
|
|
{
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
status = vxge_hal_set_behavior_on_failure(vdev->devh,
|
|
vdev->config.port_failure);
|
|
|
|
device_printf(vdev->ndev,
|
|
"port behaviour on failure change %s\n",
|
|
(status == VXGE_HAL_OK) ? "successful" : "failed");
|
|
|
|
if (status == VXGE_HAL_OK)
|
|
vxge_hal_set_fw_api(vdev->devh, 0ULL,
|
|
VXGE_HAL_API_FUNC_MODE_COMMIT,
|
|
0, 0ULL, 0ULL);
|
|
|
|
return (status);
|
|
}
|
|
|
|
void
|
|
vxge_active_port_update(vxge_dev_t *vdev)
|
|
{
|
|
u64 active_config;
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
active_config = VXGE_DEFAULT_CONFIG_VALUE;
|
|
status = vxge_hal_get_active_config(vdev->devh,
|
|
VXGE_HAL_XMAC_NWIF_ActConfig_ActivePort,
|
|
&active_config);
|
|
|
|
if (status == VXGE_HAL_OK)
|
|
vdev->active_port = active_config;
|
|
}
|
|
|
|
vxge_hal_status_e
|
|
vxge_l2switch_mode_set(vxge_dev_t *vdev)
|
|
{
|
|
vxge_hal_status_e status = VXGE_HAL_FAIL;
|
|
|
|
status = vxge_hal_set_l2switch_mode(vdev->devh,
|
|
vdev->config.l2_switch);
|
|
|
|
device_printf(vdev->ndev, "L2 switch %s\n",
|
|
(status == VXGE_HAL_OK) ?
|
|
(vdev->config.l2_switch) ? "enable" : "disable" :
|
|
"change failed");
|
|
|
|
if (status == VXGE_HAL_OK)
|
|
vxge_hal_set_fw_api(vdev->devh, 0ULL,
|
|
VXGE_HAL_API_FUNC_MODE_COMMIT,
|
|
0, 0ULL, 0ULL);
|
|
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* vxge_promisc_set
|
|
* Enable Promiscuous Mode
|
|
*/
|
|
void
|
|
vxge_promisc_set(vxge_dev_t *vdev)
|
|
{
|
|
int i;
|
|
ifnet_t ifp;
|
|
vxge_hal_vpath_h vpath_handle;
|
|
|
|
if (!vdev->is_initialized)
|
|
return;
|
|
|
|
ifp = vdev->ifp;
|
|
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath_handle = vxge_vpath_handle_get(vdev, i);
|
|
if (!vpath_handle)
|
|
continue;
|
|
|
|
if (ifp->if_flags & IFF_PROMISC)
|
|
vxge_hal_vpath_promisc_enable(vpath_handle);
|
|
else
|
|
vxge_hal_vpath_promisc_disable(vpath_handle);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_change_mtu
|
|
* Change interface MTU to a requested valid size
|
|
*/
|
|
int
|
|
vxge_change_mtu(vxge_dev_t *vdev, unsigned long new_mtu)
|
|
{
|
|
int err = EINVAL;
|
|
|
|
if ((new_mtu < VXGE_HAL_MIN_MTU) || (new_mtu > VXGE_HAL_MAX_MTU))
|
|
goto _exit0;
|
|
|
|
(vdev->ifp)->if_mtu = new_mtu;
|
|
device_printf(vdev->ndev, "MTU changed to %u\n", (vdev->ifp)->if_mtu);
|
|
|
|
if (vdev->is_initialized) {
|
|
if_down(vdev->ifp);
|
|
vxge_reset(vdev);
|
|
if_up(vdev->ifp);
|
|
}
|
|
err = 0;
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* Creates DMA tags for both Tx and Rx
|
|
*/
|
|
int
|
|
vxge_dma_tags_create(vxge_vpath_t *vpath)
|
|
{
|
|
int err = 0;
|
|
bus_size_t max_size, boundary;
|
|
vxge_dev_t *vdev = vpath->vdev;
|
|
ifnet_t ifp = vdev->ifp;
|
|
|
|
max_size = ifp->if_mtu +
|
|
VXGE_HAL_MAC_HEADER_MAX_SIZE +
|
|
VXGE_HAL_HEADER_ETHERNET_II_802_3_ALIGN;
|
|
|
|
VXGE_BUFFER_ALIGN(max_size, 128)
|
|
if (max_size <= MCLBYTES)
|
|
vdev->rx_mbuf_sz = MCLBYTES;
|
|
else
|
|
vdev->rx_mbuf_sz =
|
|
(max_size > MJUMPAGESIZE) ? MJUM9BYTES : MJUMPAGESIZE;
|
|
|
|
boundary = (max_size > PAGE_SIZE) ? 0 : PAGE_SIZE;
|
|
|
|
/* DMA tag for Tx */
|
|
err = bus_dma_tag_create(
|
|
bus_get_dma_tag(vdev->ndev),
|
|
1,
|
|
PAGE_SIZE,
|
|
BUS_SPACE_MAXADDR,
|
|
BUS_SPACE_MAXADDR,
|
|
NULL,
|
|
NULL,
|
|
VXGE_TSO_SIZE,
|
|
VXGE_MAX_SEGS,
|
|
PAGE_SIZE,
|
|
BUS_DMA_ALLOCNOW,
|
|
NULL,
|
|
NULL,
|
|
&(vpath->dma_tag_tx));
|
|
if (err != 0)
|
|
goto _exit0;
|
|
|
|
/* DMA tag for Rx */
|
|
err = bus_dma_tag_create(
|
|
bus_get_dma_tag(vdev->ndev),
|
|
1,
|
|
boundary,
|
|
BUS_SPACE_MAXADDR,
|
|
BUS_SPACE_MAXADDR,
|
|
NULL,
|
|
NULL,
|
|
vdev->rx_mbuf_sz,
|
|
1,
|
|
vdev->rx_mbuf_sz,
|
|
BUS_DMA_ALLOCNOW,
|
|
NULL,
|
|
NULL,
|
|
&(vpath->dma_tag_rx));
|
|
if (err != 0)
|
|
goto _exit1;
|
|
|
|
/* Create DMA map for this descriptor */
|
|
err = bus_dmamap_create(vpath->dma_tag_rx, BUS_DMA_NOWAIT,
|
|
&vpath->extra_dma_map);
|
|
if (err == 0)
|
|
goto _exit0;
|
|
|
|
bus_dma_tag_destroy(vpath->dma_tag_rx);
|
|
|
|
_exit1:
|
|
bus_dma_tag_destroy(vpath->dma_tag_tx);
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
static inline int
|
|
vxge_dma_mbuf_coalesce(bus_dma_tag_t dma_tag_tx, bus_dmamap_t dma_map,
|
|
mbuf_t * m_headp, bus_dma_segment_t * dma_buffers,
|
|
int *num_segs)
|
|
{
|
|
int err = 0;
|
|
mbuf_t mbuf_pkt = NULL;
|
|
|
|
retry:
|
|
err = bus_dmamap_load_mbuf_sg(dma_tag_tx, dma_map, *m_headp,
|
|
dma_buffers, num_segs, BUS_DMA_NOWAIT);
|
|
if (err == EFBIG) {
|
|
/* try to defrag, too many segments */
|
|
mbuf_pkt = m_defrag(*m_headp, M_NOWAIT);
|
|
if (mbuf_pkt == NULL) {
|
|
err = ENOBUFS;
|
|
goto _exit0;
|
|
}
|
|
*m_headp = mbuf_pkt;
|
|
goto retry;
|
|
}
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
int
|
|
vxge_device_hw_info_get(vxge_dev_t *vdev)
|
|
{
|
|
int i, err = ENXIO;
|
|
u64 vpath_mask = 0;
|
|
u32 max_supported_vpath = 0;
|
|
u32 fw_ver_maj_min;
|
|
vxge_firmware_upgrade_e fw_option;
|
|
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
vxge_hal_device_hw_info_t *hw_info;
|
|
|
|
status = vxge_hal_device_hw_info_get(vdev->pdev,
|
|
(pci_reg_h) vdev->pdev->reg_map[0],
|
|
(u8 *) vdev->pdev->bar_info[0],
|
|
&vdev->config.hw_info);
|
|
|
|
if (status != VXGE_HAL_OK)
|
|
goto _exit0;
|
|
|
|
hw_info = &vdev->config.hw_info;
|
|
|
|
vpath_mask = hw_info->vpath_mask;
|
|
if (vpath_mask == 0) {
|
|
device_printf(vdev->ndev, "No vpaths available in device\n");
|
|
goto _exit0;
|
|
}
|
|
|
|
fw_option = vdev->config.fw_option;
|
|
|
|
/* Check how many vpaths are available */
|
|
for (i = 0; i < VXGE_HAL_MAX_VIRTUAL_PATHS; i++) {
|
|
if (!((vpath_mask) & mBIT(i)))
|
|
continue;
|
|
max_supported_vpath++;
|
|
}
|
|
|
|
vdev->max_supported_vpath = max_supported_vpath;
|
|
status = vxge_hal_device_is_privileged(hw_info->host_type,
|
|
hw_info->func_id);
|
|
vdev->is_privilaged = (status == VXGE_HAL_OK) ? TRUE : FALSE;
|
|
|
|
vdev->hw_fw_version = VXGE_FW_VERSION(
|
|
hw_info->fw_version.major,
|
|
hw_info->fw_version.minor,
|
|
hw_info->fw_version.build);
|
|
|
|
fw_ver_maj_min =
|
|
VXGE_FW_MAJ_MIN_VERSION(hw_info->fw_version.major,
|
|
hw_info->fw_version.minor);
|
|
|
|
if ((fw_option >= VXGE_FW_UPGRADE_FORCE) ||
|
|
(vdev->hw_fw_version != VXGE_DRV_FW_VERSION)) {
|
|
|
|
/* For fw_ver 1.8.1 and above ignore build number. */
|
|
if ((fw_option == VXGE_FW_UPGRADE_ALL) &&
|
|
((vdev->hw_fw_version >= VXGE_FW_VERSION(1, 8, 1)) &&
|
|
(fw_ver_maj_min == VXGE_DRV_FW_MAJ_MIN_VERSION))) {
|
|
goto _exit1;
|
|
}
|
|
|
|
if (vdev->hw_fw_version < VXGE_BASE_FW_VERSION) {
|
|
device_printf(vdev->ndev,
|
|
"Upgrade driver through vxge_update, "
|
|
"Unable to load the driver.\n");
|
|
goto _exit0;
|
|
}
|
|
vdev->fw_upgrade = TRUE;
|
|
}
|
|
|
|
_exit1:
|
|
err = 0;
|
|
|
|
_exit0:
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_device_hw_info_print
|
|
* Print device and driver information
|
|
*/
|
|
void
|
|
vxge_device_hw_info_print(vxge_dev_t *vdev)
|
|
{
|
|
u32 i;
|
|
device_t ndev;
|
|
struct sysctl_ctx_list *ctx;
|
|
struct sysctl_oid_list *children;
|
|
char pmd_type[2][VXGE_PMD_INFO_LEN];
|
|
|
|
vxge_hal_device_t *hldev;
|
|
vxge_hal_device_hw_info_t *hw_info;
|
|
vxge_hal_device_pmd_info_t *pmd_port;
|
|
|
|
hldev = vdev->devh;
|
|
ndev = vdev->ndev;
|
|
|
|
ctx = device_get_sysctl_ctx(ndev);
|
|
children = SYSCTL_CHILDREN(device_get_sysctl_tree(ndev));
|
|
|
|
hw_info = &(vdev->config.hw_info);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_DRV_VERSION],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_DRV_VERSION]),
|
|
"%d.%d.%d.%d", XGELL_VERSION_MAJOR, XGELL_VERSION_MINOR,
|
|
XGELL_VERSION_FIX, XGELL_VERSION_BUILD);
|
|
|
|
/* Print PCI-e bus type/speed/width info */
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_PCIE_INFO],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PCIE_INFO]),
|
|
"x%d", hldev->link_width);
|
|
|
|
if (hldev->link_width <= VXGE_HAL_PCI_E_LINK_WIDTH_X4)
|
|
device_printf(ndev, "For optimal performance a x8 "
|
|
"PCI-Express slot is required.\n");
|
|
|
|
vxge_null_terminate((char *) hw_info->serial_number,
|
|
sizeof(hw_info->serial_number));
|
|
|
|
vxge_null_terminate((char *) hw_info->part_number,
|
|
sizeof(hw_info->part_number));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_SERIAL_NO],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_SERIAL_NO]),
|
|
"%s", hw_info->serial_number);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_PART_NO],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PART_NO]),
|
|
"%s", hw_info->part_number);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FW_VERSION],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FW_VERSION]),
|
|
"%s", hw_info->fw_version.version);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FW_DATE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FW_DATE]),
|
|
"%s", hw_info->fw_date.date);
|
|
|
|
pmd_port = &(hw_info->pmd_port0);
|
|
for (i = 0; i < hw_info->ports; i++) {
|
|
|
|
vxge_pmd_port_type_get(vdev, pmd_port->type,
|
|
pmd_type[i], sizeof(pmd_type[i]));
|
|
|
|
strncpy(vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0 + i],
|
|
"vendor=??, sn=??, pn=??, type=??",
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0 + i]));
|
|
|
|
vxge_null_terminate(pmd_port->vendor, sizeof(pmd_port->vendor));
|
|
if (strlen(pmd_port->vendor) == 0) {
|
|
pmd_port = &(hw_info->pmd_port1);
|
|
continue;
|
|
}
|
|
|
|
vxge_null_terminate(pmd_port->ser_num,
|
|
sizeof(pmd_port->ser_num));
|
|
|
|
vxge_null_terminate(pmd_port->part_num,
|
|
sizeof(pmd_port->part_num));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0 + i],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0 + i]),
|
|
"vendor=%s, sn=%s, pn=%s, type=%s",
|
|
pmd_port->vendor, pmd_port->ser_num,
|
|
pmd_port->part_num, pmd_type[i]);
|
|
|
|
pmd_port = &(hw_info->pmd_port1);
|
|
}
|
|
|
|
switch (hw_info->function_mode) {
|
|
case VXGE_HAL_PCIE_FUNC_MODE_SF1_VP17:
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]),
|
|
"%s %d %s", "Single Function - 1 function(s)",
|
|
vdev->max_supported_vpath, "VPath(s)/function");
|
|
break;
|
|
|
|
case VXGE_HAL_PCIE_FUNC_MODE_MF2_VP8:
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]),
|
|
"%s %d %s", "Multi Function - 2 function(s)",
|
|
vdev->max_supported_vpath, "VPath(s)/function");
|
|
break;
|
|
|
|
case VXGE_HAL_PCIE_FUNC_MODE_MF4_VP4:
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]),
|
|
"%s %d %s", "Multi Function - 4 function(s)",
|
|
vdev->max_supported_vpath, "VPath(s)/function");
|
|
break;
|
|
|
|
case VXGE_HAL_PCIE_FUNC_MODE_MF8_VP2:
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]),
|
|
"%s %d %s", "Multi Function - 8 function(s)",
|
|
vdev->max_supported_vpath, "VPath(s)/function");
|
|
break;
|
|
|
|
case VXGE_HAL_PCIE_FUNC_MODE_MF8P_VP2:
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]),
|
|
"%s %d %s", "Multi Function (DirectIO) - 8 function(s)",
|
|
vdev->max_supported_vpath, "VPath(s)/function");
|
|
break;
|
|
}
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_INTR_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_INTR_MODE]),
|
|
"%s", ((vdev->config.intr_mode == VXGE_HAL_INTR_MODE_MSIX) ?
|
|
"MSI-X" : "INTA"));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_VPATH_COUNT],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_VPATH_COUNT]),
|
|
"%d", vdev->no_of_vpath);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_MTU_SIZE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_MTU_SIZE]),
|
|
"%u", vdev->ifp->if_mtu);
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_LRO_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_LRO_MODE]),
|
|
"%s", ((vdev->config.lro_enable) ? "Enabled" : "Disabled"));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_RTH_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_RTH_MODE]),
|
|
"%s", ((vdev->config.rth_enable) ? "Enabled" : "Disabled"));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_TSO_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_TSO_MODE]),
|
|
"%s", ((vdev->ifp->if_capenable & IFCAP_TSO4) ?
|
|
"Enabled" : "Disabled"));
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_ADAPTER_TYPE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_ADAPTER_TYPE]),
|
|
"%s", ((hw_info->ports == 1) ? "Single Port" : "Dual Port"));
|
|
|
|
if (vdev->is_privilaged) {
|
|
|
|
if (hw_info->ports > 1) {
|
|
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_PORT_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PORT_MODE]),
|
|
"%s", vxge_port_mode[vdev->port_mode]);
|
|
|
|
if (vdev->port_mode != VXGE_HAL_DP_NP_MODE_SINGLE_PORT)
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_PORT_FAILURE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_PORT_FAILURE]),
|
|
"%s", vxge_port_failure[vdev->port_failure]);
|
|
|
|
vxge_active_port_update(vdev);
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_ACTIVE_PORT],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_ACTIVE_PORT]),
|
|
"%lld", vdev->active_port);
|
|
}
|
|
|
|
if (!is_single_func(hw_info->function_mode)) {
|
|
snprintf(vdev->config.nic_attr[VXGE_PRINT_L2SWITCH_MODE],
|
|
sizeof(vdev->config.nic_attr[VXGE_PRINT_L2SWITCH_MODE]),
|
|
"%s", ((vdev->l2_switch) ? "Enabled" : "Disabled"));
|
|
}
|
|
}
|
|
|
|
device_printf(ndev, "Driver version\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_DRV_VERSION]);
|
|
|
|
device_printf(ndev, "Serial number\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_SERIAL_NO]);
|
|
|
|
device_printf(ndev, "Part number\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PART_NO]);
|
|
|
|
device_printf(ndev, "Firmware version\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_FW_VERSION]);
|
|
|
|
device_printf(ndev, "Firmware date\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_FW_DATE]);
|
|
|
|
device_printf(ndev, "Link width\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PCIE_INFO]);
|
|
|
|
if (vdev->is_privilaged) {
|
|
device_printf(ndev, "Function mode\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE]);
|
|
}
|
|
|
|
device_printf(ndev, "Interrupt type\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_INTR_MODE]);
|
|
|
|
device_printf(ndev, "VPath(s) opened\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_VPATH_COUNT]);
|
|
|
|
device_printf(ndev, "Adapter Type\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_ADAPTER_TYPE]);
|
|
|
|
device_printf(ndev, "PMD Port 0\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0]);
|
|
|
|
if (hw_info->ports > 1) {
|
|
device_printf(ndev, "PMD Port 1\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_1]);
|
|
|
|
if (vdev->is_privilaged) {
|
|
device_printf(ndev, "Port Mode\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PORT_MODE]);
|
|
|
|
if (vdev->port_mode != VXGE_HAL_DP_NP_MODE_SINGLE_PORT)
|
|
device_printf(ndev, "Port Failure\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_PORT_FAILURE]);
|
|
|
|
device_printf(vdev->ndev, "Active Port\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_ACTIVE_PORT]);
|
|
}
|
|
}
|
|
|
|
if (vdev->is_privilaged && !is_single_func(hw_info->function_mode)) {
|
|
device_printf(vdev->ndev, "L2 Switch\t: %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_L2SWITCH_MODE]);
|
|
}
|
|
|
|
device_printf(ndev, "MTU is %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_MTU_SIZE]);
|
|
|
|
device_printf(ndev, "LRO %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_LRO_MODE]);
|
|
|
|
device_printf(ndev, "RTH %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_RTH_MODE]);
|
|
|
|
device_printf(ndev, "TSO %s\n",
|
|
vdev->config.nic_attr[VXGE_PRINT_TSO_MODE]);
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Driver version", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_DRV_VERSION],
|
|
0, "Driver version");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Serial number", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_SERIAL_NO],
|
|
0, "Serial number");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Part number", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PART_NO],
|
|
0, "Part number");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Firmware version", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_FW_VERSION],
|
|
0, "Firmware version");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Firmware date", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_FW_DATE],
|
|
0, "Firmware date");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Link width", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PCIE_INFO],
|
|
0, "Link width");
|
|
|
|
if (vdev->is_privilaged) {
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Function mode", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_FUNC_MODE],
|
|
0, "Function mode");
|
|
}
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Interrupt type", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_INTR_MODE],
|
|
0, "Interrupt type");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "VPath(s) opened", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_VPATH_COUNT],
|
|
0, "VPath(s) opened");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Adapter Type", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_ADAPTER_TYPE],
|
|
0, "Adapter Type");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "pmd port 0", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_0],
|
|
0, "pmd port");
|
|
|
|
if (hw_info->ports > 1) {
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "pmd port 1", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PMD_PORTS_1],
|
|
0, "pmd port");
|
|
|
|
if (vdev->is_privilaged) {
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Port Mode", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PORT_MODE],
|
|
0, "Port Mode");
|
|
|
|
if (vdev->port_mode != VXGE_HAL_DP_NP_MODE_SINGLE_PORT)
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "Port Failure", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_PORT_FAILURE],
|
|
0, "Port Failure");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "L2 Switch", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_L2SWITCH_MODE],
|
|
0, "L2 Switch");
|
|
}
|
|
}
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "LRO mode", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_LRO_MODE],
|
|
0, "LRO mode");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "RTH mode", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_RTH_MODE],
|
|
0, "RTH mode");
|
|
|
|
SYSCTL_ADD_STRING(ctx, children,
|
|
OID_AUTO, "TSO mode", CTLFLAG_RD,
|
|
vdev->config.nic_attr[VXGE_PRINT_TSO_MODE],
|
|
0, "TSO mode");
|
|
}
|
|
|
|
void
|
|
vxge_pmd_port_type_get(vxge_dev_t *vdev, u32 port_type,
|
|
char *ifm_name, u8 ifm_len)
|
|
{
|
|
|
|
vdev->ifm_optics = IFM_UNKNOWN;
|
|
|
|
switch (port_type) {
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_SR:
|
|
vdev->ifm_optics = IFM_10G_SR;
|
|
strlcpy(ifm_name, "10GbE SR", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_LR:
|
|
vdev->ifm_optics = IFM_10G_LR;
|
|
strlcpy(ifm_name, "10GbE LR", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_LRM:
|
|
vdev->ifm_optics = IFM_10G_LRM;
|
|
strlcpy(ifm_name, "10GbE LRM", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_DIRECT:
|
|
vdev->ifm_optics = IFM_10G_TWINAX;
|
|
strlcpy(ifm_name, "10GbE DA (Direct Attached)", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_CX4:
|
|
vdev->ifm_optics = IFM_10G_CX4;
|
|
strlcpy(ifm_name, "10GbE CX4", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_BASE_T:
|
|
#if __FreeBSD_version >= 800000
|
|
vdev->ifm_optics = IFM_10G_T;
|
|
#endif
|
|
strlcpy(ifm_name, "10GbE baseT", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_10G_OTHER:
|
|
strlcpy(ifm_name, "10GbE Other", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_SX:
|
|
vdev->ifm_optics = IFM_1000_SX;
|
|
strlcpy(ifm_name, "1GbE SX", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_LX:
|
|
vdev->ifm_optics = IFM_1000_LX;
|
|
strlcpy(ifm_name, "1GbE LX", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_CX:
|
|
vdev->ifm_optics = IFM_1000_CX;
|
|
strlcpy(ifm_name, "1GbE CX", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_BASE_T:
|
|
vdev->ifm_optics = IFM_1000_T;
|
|
strlcpy(ifm_name, "1GbE baseT", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_DIRECT:
|
|
strlcpy(ifm_name, "1GbE DA (Direct Attached)",
|
|
ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_CX4:
|
|
strlcpy(ifm_name, "1GbE CX4", ifm_len);
|
|
break;
|
|
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_1G_OTHER:
|
|
strlcpy(ifm_name, "1GbE Other", ifm_len);
|
|
break;
|
|
|
|
default:
|
|
case VXGE_HAL_DEVICE_PMD_TYPE_UNKNOWN:
|
|
strlcpy(ifm_name, "UNSUP", ifm_len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
u32
|
|
vxge_ring_length_get(u32 buffer_mode)
|
|
{
|
|
return (VXGE_DEFAULT_RING_BLOCK *
|
|
vxge_hal_ring_rxds_per_block_get(buffer_mode));
|
|
}
|
|
|
|
/*
|
|
* Removes trailing spaces padded
|
|
* and NULL terminates strings
|
|
*/
|
|
static inline void
|
|
vxge_null_terminate(char *str, size_t len)
|
|
{
|
|
len--;
|
|
while (*str && (*str != ' ') && (len != 0))
|
|
++str;
|
|
|
|
--len;
|
|
if (*str)
|
|
*str = '\0';
|
|
}
|
|
|
|
/*
|
|
* vxge_ioctl
|
|
* Callback to control the device
|
|
*/
|
|
int
|
|
vxge_ioctl(ifnet_t ifp, u_long command, caddr_t data)
|
|
{
|
|
int mask, err = 0;
|
|
vxge_dev_t *vdev = (vxge_dev_t *) ifp->if_softc;
|
|
struct ifreq *ifr = (struct ifreq *) data;
|
|
|
|
if (!vdev->is_active)
|
|
return (EBUSY);
|
|
|
|
switch (command) {
|
|
/* Set/Get ifnet address */
|
|
case SIOCSIFADDR:
|
|
case SIOCGIFADDR:
|
|
ether_ioctl(ifp, command, data);
|
|
break;
|
|
|
|
/* Set Interface MTU */
|
|
case SIOCSIFMTU:
|
|
err = vxge_change_mtu(vdev, (unsigned long)ifr->ifr_mtu);
|
|
break;
|
|
|
|
/* Set Interface Flags */
|
|
case SIOCSIFFLAGS:
|
|
VXGE_DRV_LOCK(vdev);
|
|
if (ifp->if_flags & IFF_UP) {
|
|
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
|
|
if ((ifp->if_flags ^ vdev->if_flags) &
|
|
(IFF_PROMISC | IFF_ALLMULTI))
|
|
vxge_promisc_set(vdev);
|
|
} else {
|
|
vxge_init_locked(vdev);
|
|
}
|
|
} else {
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
|
vxge_stop_locked(vdev);
|
|
}
|
|
vdev->if_flags = ifp->if_flags;
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
break;
|
|
|
|
/* Add/delete multicast address */
|
|
case SIOCADDMULTI:
|
|
case SIOCDELMULTI:
|
|
break;
|
|
|
|
/* Get/Set Interface Media */
|
|
case SIOCSIFMEDIA:
|
|
case SIOCGIFMEDIA:
|
|
err = ifmedia_ioctl(ifp, ifr, &vdev->media, command);
|
|
break;
|
|
|
|
/* Set Capabilities */
|
|
case SIOCSIFCAP:
|
|
VXGE_DRV_LOCK(vdev);
|
|
mask = ifr->ifr_reqcap ^ ifp->if_capenable;
|
|
|
|
if (mask & IFCAP_TXCSUM) {
|
|
ifp->if_capenable ^= IFCAP_TXCSUM;
|
|
ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
|
|
|
|
if ((ifp->if_capenable & IFCAP_TSO) &&
|
|
!(ifp->if_capenable & IFCAP_TXCSUM)) {
|
|
|
|
ifp->if_capenable &= ~IFCAP_TSO;
|
|
ifp->if_hwassist &= ~CSUM_TSO;
|
|
if_printf(ifp, "TSO Disabled\n");
|
|
}
|
|
}
|
|
if (mask & IFCAP_RXCSUM)
|
|
ifp->if_capenable ^= IFCAP_RXCSUM;
|
|
|
|
if (mask & IFCAP_TSO4) {
|
|
ifp->if_capenable ^= IFCAP_TSO4;
|
|
|
|
if (ifp->if_capenable & IFCAP_TSO) {
|
|
if (ifp->if_capenable & IFCAP_TXCSUM) {
|
|
ifp->if_hwassist |= CSUM_TSO;
|
|
if_printf(ifp, "TSO Enabled\n");
|
|
} else {
|
|
ifp->if_capenable &= ~IFCAP_TSO;
|
|
ifp->if_hwassist &= ~CSUM_TSO;
|
|
if_printf(ifp,
|
|
"Enable tx checksum offload \
|
|
first.\n");
|
|
err = EAGAIN;
|
|
}
|
|
} else {
|
|
ifp->if_hwassist &= ~CSUM_TSO;
|
|
if_printf(ifp, "TSO Disabled\n");
|
|
}
|
|
}
|
|
if (mask & IFCAP_LRO)
|
|
ifp->if_capenable ^= IFCAP_LRO;
|
|
|
|
if (mask & IFCAP_VLAN_HWTAGGING)
|
|
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
|
|
|
|
if (mask & IFCAP_VLAN_MTU)
|
|
ifp->if_capenable ^= IFCAP_VLAN_MTU;
|
|
|
|
if (mask & IFCAP_VLAN_HWCSUM)
|
|
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
|
|
|
|
#if __FreeBSD_version >= 800000
|
|
if (mask & IFCAP_VLAN_HWTSO)
|
|
ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
|
|
#endif
|
|
|
|
#if defined(VLAN_CAPABILITIES)
|
|
VLAN_CAPABILITIES(ifp);
|
|
#endif
|
|
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
break;
|
|
|
|
case SIOCGPRIVATE_0:
|
|
VXGE_DRV_LOCK(vdev);
|
|
err = vxge_ioctl_stats(vdev, ifr);
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
break;
|
|
|
|
case SIOCGPRIVATE_1:
|
|
VXGE_DRV_LOCK(vdev);
|
|
err = vxge_ioctl_regs(vdev, ifr);
|
|
VXGE_DRV_UNLOCK(vdev);
|
|
break;
|
|
|
|
default:
|
|
err = ether_ioctl(ifp, command, data);
|
|
break;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_ioctl_regs
|
|
* IOCTL to get registers
|
|
*/
|
|
int
|
|
vxge_ioctl_regs(vxge_dev_t *vdev, struct ifreq *ifr)
|
|
{
|
|
u64 value = 0x0;
|
|
u32 vp_id = 0;
|
|
u32 offset, reqd_size = 0;
|
|
int i, err = EINVAL;
|
|
|
|
char *command = (char *) ifr->ifr_data;
|
|
void *reg_info = (void *) ifr->ifr_data;
|
|
|
|
vxge_vpath_t *vpath;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
vxge_hal_mgmt_reg_type_e regs_type;
|
|
|
|
switch (*command) {
|
|
case vxge_hal_mgmt_reg_type_pcicfgmgmt:
|
|
if (vdev->is_privilaged) {
|
|
reqd_size = sizeof(vxge_hal_pcicfgmgmt_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_pcicfgmgmt;
|
|
}
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_mrpcim:
|
|
if (vdev->is_privilaged) {
|
|
reqd_size = sizeof(vxge_hal_mrpcim_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_mrpcim;
|
|
}
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_srpcim:
|
|
if (vdev->is_privilaged) {
|
|
reqd_size = sizeof(vxge_hal_srpcim_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_srpcim;
|
|
}
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_memrepair:
|
|
if (vdev->is_privilaged) {
|
|
/* reqd_size = sizeof(vxge_hal_memrepair_reg_t); */
|
|
regs_type = vxge_hal_mgmt_reg_type_memrepair;
|
|
}
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_legacy:
|
|
reqd_size = sizeof(vxge_hal_legacy_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_legacy;
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_toc:
|
|
reqd_size = sizeof(vxge_hal_toc_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_toc;
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_common:
|
|
reqd_size = sizeof(vxge_hal_common_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_common;
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_vpmgmt:
|
|
reqd_size = sizeof(vxge_hal_vpmgmt_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_vpmgmt;
|
|
vpath = &(vdev->vpaths[*((u32 *) reg_info + 1)]);
|
|
vp_id = vpath->vp_id;
|
|
break;
|
|
|
|
case vxge_hal_mgmt_reg_type_vpath:
|
|
reqd_size = sizeof(vxge_hal_vpath_reg_t);
|
|
regs_type = vxge_hal_mgmt_reg_type_vpath;
|
|
vpath = &(vdev->vpaths[*((u32 *) reg_info + 1)]);
|
|
vp_id = vpath->vp_id;
|
|
break;
|
|
|
|
case VXGE_GET_VPATH_COUNT:
|
|
*((u32 *) reg_info) = vdev->no_of_vpath;
|
|
err = 0;
|
|
break;
|
|
|
|
default:
|
|
reqd_size = 0;
|
|
break;
|
|
}
|
|
|
|
if (reqd_size) {
|
|
for (i = 0, offset = 0; offset < reqd_size;
|
|
i++, offset += 0x0008) {
|
|
value = 0x0;
|
|
status = vxge_hal_mgmt_reg_read(vdev->devh, regs_type,
|
|
vp_id, offset, &value);
|
|
|
|
err = (status != VXGE_HAL_OK) ? EINVAL : 0;
|
|
if (err == EINVAL)
|
|
break;
|
|
|
|
*((u64 *) ((u64 *) reg_info + i)) = value;
|
|
}
|
|
}
|
|
return (err);
|
|
}
|
|
|
|
/*
|
|
* vxge_ioctl_stats
|
|
* IOCTL to get statistics
|
|
*/
|
|
int
|
|
vxge_ioctl_stats(vxge_dev_t *vdev, struct ifreq *ifr)
|
|
{
|
|
int i, retsize, err = EINVAL;
|
|
u32 bufsize;
|
|
|
|
vxge_vpath_t *vpath;
|
|
vxge_bw_info_t *bw_info;
|
|
vxge_port_info_t *port_info;
|
|
vxge_drv_stats_t *drv_stat;
|
|
|
|
char *buffer = NULL;
|
|
char *command = (char *) ifr->ifr_data;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
switch (*command) {
|
|
case VXGE_GET_PCI_CONF:
|
|
bufsize = VXGE_STATS_BUFFER_SIZE;
|
|
buffer = (char *) vxge_mem_alloc(bufsize);
|
|
if (buffer != NULL) {
|
|
status = vxge_hal_aux_pci_config_read(vdev->devh,
|
|
bufsize, buffer, &retsize);
|
|
if (status == VXGE_HAL_OK)
|
|
err = copyout(buffer, ifr->ifr_data, retsize);
|
|
else
|
|
device_printf(vdev->ndev,
|
|
"failed pciconfig statistics query\n");
|
|
|
|
vxge_mem_free(buffer, bufsize);
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_MRPCIM_STATS:
|
|
if (!vdev->is_privilaged)
|
|
break;
|
|
|
|
bufsize = VXGE_STATS_BUFFER_SIZE;
|
|
buffer = (char *) vxge_mem_alloc(bufsize);
|
|
if (buffer != NULL) {
|
|
status = vxge_hal_aux_stats_mrpcim_read(vdev->devh,
|
|
bufsize, buffer, &retsize);
|
|
if (status == VXGE_HAL_OK)
|
|
err = copyout(buffer, ifr->ifr_data, retsize);
|
|
else
|
|
device_printf(vdev->ndev,
|
|
"failed mrpcim statistics query\n");
|
|
|
|
vxge_mem_free(buffer, bufsize);
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_DEVICE_STATS:
|
|
bufsize = VXGE_STATS_BUFFER_SIZE;
|
|
buffer = (char *) vxge_mem_alloc(bufsize);
|
|
if (buffer != NULL) {
|
|
status = vxge_hal_aux_stats_device_read(vdev->devh,
|
|
bufsize, buffer, &retsize);
|
|
if (status == VXGE_HAL_OK)
|
|
err = copyout(buffer, ifr->ifr_data, retsize);
|
|
else
|
|
device_printf(vdev->ndev,
|
|
"failed device statistics query\n");
|
|
|
|
vxge_mem_free(buffer, bufsize);
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_DEVICE_HWINFO:
|
|
bufsize = sizeof(vxge_device_hw_info_t);
|
|
buffer = (char *) vxge_mem_alloc(bufsize);
|
|
if (buffer != NULL) {
|
|
vxge_os_memcpy(
|
|
&(((vxge_device_hw_info_t *) buffer)->hw_info),
|
|
&vdev->config.hw_info,
|
|
sizeof(vxge_hal_device_hw_info_t));
|
|
|
|
((vxge_device_hw_info_t *) buffer)->port_mode =
|
|
vdev->port_mode;
|
|
|
|
((vxge_device_hw_info_t *) buffer)->port_failure =
|
|
vdev->port_failure;
|
|
|
|
err = copyout(buffer, ifr->ifr_data, bufsize);
|
|
if (err != 0)
|
|
device_printf(vdev->ndev,
|
|
"failed device hardware info query\n");
|
|
|
|
vxge_mem_free(buffer, bufsize);
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_DRIVER_STATS:
|
|
bufsize = sizeof(vxge_drv_stats_t) * vdev->no_of_vpath;
|
|
drv_stat = (vxge_drv_stats_t *) vxge_mem_alloc(bufsize);
|
|
if (drv_stat != NULL) {
|
|
for (i = 0; i < vdev->no_of_vpath; i++) {
|
|
vpath = &(vdev->vpaths[i]);
|
|
|
|
vpath->driver_stats.rx_lro_queued +=
|
|
vpath->lro.lro_queued;
|
|
|
|
vpath->driver_stats.rx_lro_flushed +=
|
|
vpath->lro.lro_flushed;
|
|
|
|
vxge_os_memcpy(&drv_stat[i],
|
|
&(vpath->driver_stats),
|
|
sizeof(vxge_drv_stats_t));
|
|
}
|
|
|
|
err = copyout(drv_stat, ifr->ifr_data, bufsize);
|
|
if (err != 0)
|
|
device_printf(vdev->ndev,
|
|
"failed driver statistics query\n");
|
|
|
|
vxge_mem_free(drv_stat, bufsize);
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_BANDWIDTH:
|
|
bw_info = (vxge_bw_info_t *) ifr->ifr_data;
|
|
|
|
if ((vdev->config.hw_info.func_id != 0) &&
|
|
(vdev->hw_fw_version < VXGE_FW_VERSION(1, 8, 0)))
|
|
break;
|
|
|
|
if (vdev->config.hw_info.func_id != 0)
|
|
bw_info->func_id = vdev->config.hw_info.func_id;
|
|
|
|
status = vxge_bw_priority_get(vdev, bw_info);
|
|
if (status != VXGE_HAL_OK)
|
|
break;
|
|
|
|
err = copyout(bw_info, ifr->ifr_data, sizeof(vxge_bw_info_t));
|
|
break;
|
|
|
|
case VXGE_SET_BANDWIDTH:
|
|
if (vdev->is_privilaged)
|
|
err = vxge_bw_priority_set(vdev, ifr);
|
|
break;
|
|
|
|
case VXGE_SET_PORT_MODE:
|
|
if (vdev->is_privilaged) {
|
|
if (vdev->config.hw_info.ports == VXGE_DUAL_PORT_MODE) {
|
|
port_info = (vxge_port_info_t *) ifr->ifr_data;
|
|
vdev->config.port_mode = port_info->port_mode;
|
|
err = vxge_port_mode_update(vdev);
|
|
if (err != ENXIO)
|
|
err = VXGE_HAL_FAIL;
|
|
else {
|
|
err = VXGE_HAL_OK;
|
|
device_printf(vdev->ndev,
|
|
"PLEASE POWER CYCLE THE SYSTEM\n");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VXGE_GET_PORT_MODE:
|
|
if (vdev->is_privilaged) {
|
|
if (vdev->config.hw_info.ports == VXGE_DUAL_PORT_MODE) {
|
|
port_info = (vxge_port_info_t *) ifr->ifr_data;
|
|
err = vxge_port_mode_get(vdev, port_info);
|
|
if (err == VXGE_HAL_OK) {
|
|
err = copyout(port_info, ifr->ifr_data,
|
|
sizeof(vxge_port_info_t));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
int
|
|
vxge_bw_priority_config(vxge_dev_t *vdev)
|
|
{
|
|
u32 i;
|
|
int err = EINVAL;
|
|
|
|
for (i = 0; i < vdev->no_of_func; i++) {
|
|
err = vxge_bw_priority_update(vdev, i, TRUE);
|
|
if (err != 0)
|
|
break;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
int
|
|
vxge_bw_priority_set(vxge_dev_t *vdev, struct ifreq *ifr)
|
|
{
|
|
int err;
|
|
u32 func_id;
|
|
vxge_bw_info_t *bw_info;
|
|
|
|
bw_info = (vxge_bw_info_t *) ifr->ifr_data;
|
|
func_id = bw_info->func_id;
|
|
|
|
vdev->config.bw_info[func_id].priority = bw_info->priority;
|
|
vdev->config.bw_info[func_id].bandwidth = bw_info->bandwidth;
|
|
|
|
err = vxge_bw_priority_update(vdev, func_id, FALSE);
|
|
|
|
return (err);
|
|
}
|
|
|
|
int
|
|
vxge_bw_priority_update(vxge_dev_t *vdev, u32 func_id, bool binit)
|
|
{
|
|
u32 i, set = 0;
|
|
u32 bandwidth, priority, vpath_count;
|
|
u64 vpath_list[VXGE_HAL_MAX_VIRTUAL_PATHS];
|
|
|
|
vxge_hal_device_t *hldev;
|
|
vxge_hal_vp_config_t *vp_config;
|
|
vxge_hal_status_e status = VXGE_HAL_OK;
|
|
|
|
hldev = vdev->devh;
|
|
|
|
status = vxge_hal_get_vpath_list(vdev->devh, func_id,
|
|
vpath_list, &vpath_count);
|
|
|
|
if (status != VXGE_HAL_OK)
|
|
return (status);
|
|
|
|
for (i = 0; i < vpath_count; i++) {
|
|
vp_config = &(hldev->config.vp_config[vpath_list[i]]);
|
|
|
|
/* Configure Bandwidth */
|
|
if (vdev->config.bw_info[func_id].bandwidth !=
|
|
VXGE_HAL_VPATH_BW_LIMIT_DEFAULT) {
|
|
|
|
set = 1;
|
|
bandwidth = vdev->config.bw_info[func_id].bandwidth;
|
|
if (bandwidth < VXGE_HAL_VPATH_BW_LIMIT_MIN ||
|
|
bandwidth > VXGE_HAL_VPATH_BW_LIMIT_MAX) {
|
|
|
|
bandwidth = VXGE_HAL_VPATH_BW_LIMIT_DEFAULT;
|
|
}
|
|
vp_config->bandwidth = bandwidth;
|
|
}
|
|
|
|
/*
|
|
* If b/w limiting is enabled on any of the
|
|
* VFs, then for remaining VFs set the priority to 3
|
|
* and b/w limiting to max i.e 10 Gb)
|
|
*/
|
|
if (vp_config->bandwidth == VXGE_HAL_VPATH_BW_LIMIT_DEFAULT)
|
|
vp_config->bandwidth = VXGE_HAL_VPATH_BW_LIMIT_MAX;
|
|
|
|
if (binit && vdev->config.low_latency) {
|
|
if (func_id == 0)
|
|
vdev->config.bw_info[func_id].priority =
|
|
VXGE_DEFAULT_VPATH_PRIORITY_HIGH;
|
|
}
|
|
|
|
/* Configure Priority */
|
|
if (vdev->config.bw_info[func_id].priority !=
|
|
VXGE_HAL_VPATH_PRIORITY_DEFAULT) {
|
|
|
|
set = 1;
|
|
priority = vdev->config.bw_info[func_id].priority;
|
|
if (priority < VXGE_HAL_VPATH_PRIORITY_MIN ||
|
|
priority > VXGE_HAL_VPATH_PRIORITY_MAX) {
|
|
|
|
priority = VXGE_HAL_VPATH_PRIORITY_DEFAULT;
|
|
}
|
|
vp_config->priority = priority;
|
|
|
|
} else if (vdev->config.low_latency) {
|
|
set = 1;
|
|
vp_config->priority = VXGE_DEFAULT_VPATH_PRIORITY_LOW;
|
|
}
|
|
|
|
if (set == 1) {
|
|
status = vxge_hal_rx_bw_priority_set(vdev->devh,
|
|
vpath_list[i]);
|
|
if (status != VXGE_HAL_OK)
|
|
break;
|
|
|
|
if (vpath_list[i] < VXGE_HAL_TX_BW_VPATH_LIMIT) {
|
|
status = vxge_hal_tx_bw_priority_set(
|
|
vdev->devh, vpath_list[i]);
|
|
if (status != VXGE_HAL_OK)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ((status == VXGE_HAL_OK) ? 0 : EINVAL);
|
|
}
|
|
|
|
/*
|
|
* vxge_intr_coalesce_tx
|
|
* Changes interrupt coalescing if the interrupts are not within a range
|
|
* Return Value: Nothing
|
|
*/
|
|
void
|
|
vxge_intr_coalesce_tx(vxge_vpath_t *vpath)
|
|
{
|
|
u32 timer;
|
|
|
|
if (!vpath->tx_intr_coalesce)
|
|
return;
|
|
|
|
vpath->tx_interrupts++;
|
|
if (ticks > vpath->tx_ticks + hz/100) {
|
|
|
|
vpath->tx_ticks = ticks;
|
|
timer = vpath->tti_rtimer_val;
|
|
if (vpath->tx_interrupts > VXGE_MAX_TX_INTERRUPT_COUNT) {
|
|
if (timer != VXGE_TTI_RTIMER_ADAPT_VAL) {
|
|
vpath->tti_rtimer_val =
|
|
VXGE_TTI_RTIMER_ADAPT_VAL;
|
|
|
|
vxge_hal_vpath_dynamic_tti_rtimer_set(
|
|
vpath->handle, vpath->tti_rtimer_val);
|
|
}
|
|
} else {
|
|
if (timer != 0) {
|
|
vpath->tti_rtimer_val = 0;
|
|
vxge_hal_vpath_dynamic_tti_rtimer_set(
|
|
vpath->handle, vpath->tti_rtimer_val);
|
|
}
|
|
}
|
|
vpath->tx_interrupts = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_intr_coalesce_rx
|
|
* Changes interrupt coalescing if the interrupts are not within a range
|
|
* Return Value: Nothing
|
|
*/
|
|
void
|
|
vxge_intr_coalesce_rx(vxge_vpath_t *vpath)
|
|
{
|
|
u32 timer;
|
|
|
|
if (!vpath->rx_intr_coalesce)
|
|
return;
|
|
|
|
vpath->rx_interrupts++;
|
|
if (ticks > vpath->rx_ticks + hz/100) {
|
|
|
|
vpath->rx_ticks = ticks;
|
|
timer = vpath->rti_rtimer_val;
|
|
|
|
if (vpath->rx_interrupts > VXGE_MAX_RX_INTERRUPT_COUNT) {
|
|
if (timer != VXGE_RTI_RTIMER_ADAPT_VAL) {
|
|
vpath->rti_rtimer_val =
|
|
VXGE_RTI_RTIMER_ADAPT_VAL;
|
|
|
|
vxge_hal_vpath_dynamic_rti_rtimer_set(
|
|
vpath->handle, vpath->rti_rtimer_val);
|
|
}
|
|
} else {
|
|
if (timer != 0) {
|
|
vpath->rti_rtimer_val = 0;
|
|
vxge_hal_vpath_dynamic_rti_rtimer_set(
|
|
vpath->handle, vpath->rti_rtimer_val);
|
|
}
|
|
}
|
|
vpath->rx_interrupts = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* vxge_methods FreeBSD device interface entry points
|
|
*/
|
|
static device_method_t vxge_methods[] = {
|
|
DEVMETHOD(device_probe, vxge_probe),
|
|
DEVMETHOD(device_attach, vxge_attach),
|
|
DEVMETHOD(device_detach, vxge_detach),
|
|
DEVMETHOD(device_shutdown, vxge_shutdown),
|
|
|
|
DEVMETHOD_END
|
|
};
|
|
|
|
static driver_t vxge_driver = {
|
|
"vxge", vxge_methods, sizeof(vxge_dev_t),
|
|
};
|
|
|
|
static devclass_t vxge_devclass;
|
|
|
|
DRIVER_MODULE(vxge, pci, vxge_driver, vxge_devclass, 0, 0);
|