1371 lines
36 KiB
C
1371 lines
36 KiB
C
/*
|
|
* Copyright (C) 2015 Mellanox Technologies Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER );
|
|
|
|
#include "../include/mlx_port.h"
|
|
#include "../include/mlx_cmd.h"
|
|
#include "../../mlx_utils/include/public/mlx_memory.h"
|
|
#include "../../mlx_utils/include/public/mlx_pci.h"
|
|
#include "../../mlx_utils/include/public/mlx_bail.h"
|
|
|
|
#define PortDataEntry( _option, _offset, _align, _mask) { \
|
|
.option = _option, \
|
|
.offset = _offset, \
|
|
.align = _align, \
|
|
.mask = _mask, \
|
|
}
|
|
|
|
#define QpDataEntry( _type, _send_offset, _recv_offset) { \
|
|
.type = _type, \
|
|
.send_offset = _send_offset, \
|
|
.recv_offset = _recv_offset, \
|
|
}
|
|
|
|
|
|
struct nodnic_port_data_entry nodnic_port_data_table[] = {
|
|
PortDataEntry(nodnic_port_option_link_type, 0x0, 4, 0x1),
|
|
PortDataEntry(nodnic_port_option_mac_low, 0xc, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_mac_high, 0x8, 0, 0xFFFF),
|
|
PortDataEntry(nodnic_port_option_log_cq_size, 0x6c, 0, 0x3F),
|
|
PortDataEntry(nodnic_port_option_reset_needed, 0x0, 31, 0x1),
|
|
PortDataEntry(nodnic_port_option_mac_filters_en, 0x4, 0, 0x1F),
|
|
PortDataEntry(nodnic_port_option_port_state, 0x0, 0, 0xF),
|
|
PortDataEntry(nodnic_port_option_network_en, 0x4, 31, 0x1),
|
|
PortDataEntry(nodnic_port_option_dma_en, 0x4, 30, 0x1),
|
|
PortDataEntry(nodnic_port_option_eq_addr_low, 0x74, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_eq_addr_high, 0x70, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_cq_addr_low, 0x6c, 12, 0xFFFFF),
|
|
PortDataEntry(nodnic_port_option_cq_addr_high, 0x68, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_port_management_change_event, 0x0, 30, 0x1),
|
|
PortDataEntry(nodnic_port_option_port_promisc_en, 0x4, 29, 0x1),
|
|
#ifndef DEVICE_CX3
|
|
PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffffff),
|
|
#else
|
|
PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffff),
|
|
#endif
|
|
PortDataEntry(nodnic_port_option_port_promisc_multicast_en, 0x4, 28, 0x1),
|
|
#ifdef DEVICE_CX3
|
|
PortDataEntry(nodnic_port_option_crspace_en, 0x4, 27, 0x1),
|
|
#endif
|
|
PortDataEntry(nodnic_port_option_send_ring0_uar_index, 0x108, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_send_ring1_uar_index, 0x10c, 0, 0xFFFFFFFF),
|
|
PortDataEntry(nodnic_port_option_cq_n_index, 0x118, 0, 0xFFFFFF),
|
|
};
|
|
|
|
#define MAX_QP_DATA_ENTRIES 5
|
|
struct nodnic_qp_data_entry nodnic_qp_data_teable[MAX_QP_DATA_ENTRIES] = {
|
|
QpDataEntry(NODNIC_QPT_SMI, 0, 0),
|
|
QpDataEntry(NODNIC_QPT_GSI, 0, 0),
|
|
QpDataEntry(NODNIC_QPT_UD, 0, 0),
|
|
QpDataEntry(NODNIC_QPT_RC, 0, 0),
|
|
QpDataEntry(NODNIC_QPT_ETH, 0x80, 0xC0),
|
|
};
|
|
|
|
#define MAX_NODNIC_PORTS 2
|
|
int nodnic_port_offset_table[MAX_NODNIC_PORTS] = {
|
|
0x100, //port 1 offset
|
|
0x280, //port 1 offset
|
|
};
|
|
|
|
mlx_status
|
|
nodnic_port_get_state(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT nodnic_port_state *state
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
|
|
status = nodnic_port_query(port_priv,
|
|
nodnic_port_option_port_state, &out);
|
|
MLX_CHECK_STATUS(port_priv->device, status, query_err,
|
|
"nodnic_port_query failed");
|
|
*state = (nodnic_port_state)out;
|
|
query_err:
|
|
return status;
|
|
}
|
|
mlx_status
|
|
nodnic_port_get_type(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT nodnic_port_type *type
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
|
|
if ( port_priv->port_type == NODNIC_PORT_TYPE_UNKNOWN){
|
|
status = nodnic_port_query(port_priv,
|
|
nodnic_port_option_link_type, &out);
|
|
MLX_FATAL_CHECK_STATUS(status, query_err,
|
|
"nodnic_port_query failed");
|
|
port_priv->port_type = (nodnic_port_type)out;
|
|
}
|
|
*type = port_priv->port_type;
|
|
query_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_query(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN nodnic_port_option option,
|
|
OUT mlx_uint32 *out
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
struct nodnic_port_data_entry *data_entry;
|
|
mlx_uint32 buffer = 0;
|
|
if( port_priv == NULL || out == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
device_priv = port_priv->device;
|
|
|
|
data_entry = &nodnic_port_data_table[option];
|
|
|
|
status = nodnic_cmd_read(device_priv,
|
|
port_priv->port_offset + data_entry->offset , &buffer);
|
|
MLX_CHECK_STATUS(device_priv, status, read_err,
|
|
"nodnic_cmd_read failed");
|
|
*out = (buffer >> data_entry->align) & data_entry->mask;
|
|
read_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_set(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN nodnic_port_option option,
|
|
IN mlx_uint32 in
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
struct nodnic_port_data_entry *data_entry;
|
|
mlx_uint32 buffer = 0;
|
|
|
|
if( port_priv == NULL ){
|
|
MLX_DEBUG_FATAL_ERROR("port_priv is NULL\n");
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
device_priv = port_priv->device;
|
|
data_entry = &nodnic_port_data_table[option];
|
|
|
|
if( in > data_entry->mask ){
|
|
MLX_DEBUG_FATAL_ERROR("in > data_entry->mask (%d > %d)\n",
|
|
in, data_entry->mask);
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
status = nodnic_cmd_read(device_priv,
|
|
port_priv->port_offset + data_entry->offset, &buffer);
|
|
MLX_FATAL_CHECK_STATUS(status, read_err,
|
|
"nodnic_cmd_read failed");
|
|
buffer = buffer & ~(data_entry->mask << data_entry->align);
|
|
buffer = buffer | (in << data_entry->align);
|
|
status = nodnic_cmd_write(device_priv,
|
|
port_priv->port_offset + data_entry->offset, buffer);
|
|
MLX_FATAL_CHECK_STATUS(status, write_err,
|
|
"nodnic_cmd_write failed");
|
|
write_err:
|
|
read_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_set_send_uar_offset(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
|
|
if ( ! port_priv->device->device_cap.support_uar_tx_db ) {
|
|
MLX_DEBUG_INFO1 ( port_priv, "nodnic_port_set_send_uar_offset: tx db using uar is not supported \n");
|
|
status = MLX_UNSUPPORTED;
|
|
goto uar_not_supported;
|
|
}
|
|
|
|
status = nodnic_port_query(port_priv,
|
|
nodnic_port_option_send_ring0_uar_index, &out);
|
|
MLX_CHECK_STATUS(port_priv->device, status, query_err,
|
|
"nodnic_port_query failed");
|
|
port_priv->device->uar.offset = out << port_priv->device->device_cap.log_uar_page_size;
|
|
uar_not_supported:
|
|
query_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_read_reset_needed(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT mlx_boolean *reset_needed
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
status = nodnic_port_query(port_priv,
|
|
nodnic_port_option_reset_needed, &out);
|
|
MLX_CHECK_STATUS(port_priv->device, status, query_err,
|
|
"nodnic_port_query failed");
|
|
*reset_needed = (mlx_boolean)out;
|
|
query_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_read_port_management_change_event(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT mlx_boolean *change_event
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
status = nodnic_port_query(port_priv,
|
|
nodnic_port_option_port_management_change_event, &out);
|
|
MLX_CHECK_STATUS(port_priv->device, status, query_err,
|
|
"nodnic_port_query failed");
|
|
*change_event = (mlx_boolean)out;
|
|
query_err:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_allocate_dbr_dma (
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_doorbell *nodnic_db,
|
|
IN mlx_uint32 dbr_addr_low_ofst,
|
|
IN mlx_uint32 dbr_addr_high_ofst,
|
|
IN void **dbr_addr,
|
|
IN mlx_size size,
|
|
IN void **map
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint64 address = 0;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL || nodnic_db == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
status = mlx_memory_alloc_dma(device_priv->utils,
|
|
size,
|
|
NODNIC_MEMORY_ALIGN,
|
|
(void **)dbr_addr
|
|
);
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_db_record_err,
|
|
"doorbell record dma allocation error");
|
|
|
|
status = mlx_memory_map_dma(device_priv->utils,
|
|
(void *)(*dbr_addr),
|
|
size,
|
|
&nodnic_db->doorbell_physical,
|
|
map//nodnic_ring->map
|
|
);
|
|
MLX_FATAL_CHECK_STATUS(status, map_db_record_err,
|
|
"doorbell record map dma error");
|
|
|
|
address = (mlx_uint64)nodnic_db->doorbell_physical;
|
|
status = nodnic_cmd_write(device_priv,
|
|
dbr_addr_low_ofst,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"failed to set doorbell addr low");
|
|
|
|
address = address >> 32;
|
|
status = nodnic_cmd_write(device_priv,
|
|
dbr_addr_high_ofst,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"failed to set doorbell addr high");
|
|
|
|
return status;
|
|
|
|
set_err:
|
|
mlx_memory_ummap_dma(device_priv->utils, *map);
|
|
map_db_record_err:
|
|
mlx_memory_free_dma(device_priv->utils, size,
|
|
(void **)dbr_addr);
|
|
alloc_db_record_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_cq_dbr_dma_init(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT nodnic_cq **cq
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
if ( ! device_priv->device_cap.support_bar_cq_ctrl ) {
|
|
status = MLX_UNSUPPORTED;
|
|
goto uar_arm_cq_db_unsupported;
|
|
}
|
|
|
|
#define NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET 0x114
|
|
#define NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET 0x110
|
|
|
|
status = nodnic_port_allocate_dbr_dma ( port_priv,&(*cq)->arm_cq_doorbell,
|
|
port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET,
|
|
port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET,
|
|
(void **)&port_priv->arm_cq_doorbell_record ,
|
|
sizeof(nodnic_arm_cq_db),
|
|
(void **)&((*cq)->arm_cq_doorbell.map));
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
|
|
"failed to allocate doorbell record dma");
|
|
return status;
|
|
|
|
alloc_dbr_dma_err:
|
|
uar_arm_cq_db_unsupported:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_create_cq(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_size cq_size,
|
|
OUT nodnic_cq **cq
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
mlx_uint64 address = 0;
|
|
if( port_priv == NULL || cq == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
|
|
status = mlx_memory_zalloc(device_priv->utils,
|
|
sizeof(nodnic_cq),(mlx_void **)cq);
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_err,
|
|
"cq priv allocation error");
|
|
|
|
(*cq)->cq_size = cq_size;
|
|
status = mlx_memory_alloc_dma(device_priv->utils,
|
|
(*cq)->cq_size, NODNIC_MEMORY_ALIGN,
|
|
&(*cq)->cq_virt);
|
|
MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
|
|
"cq allocation error");
|
|
|
|
status = mlx_memory_map_dma(device_priv->utils,
|
|
(*cq)->cq_virt,
|
|
(*cq)->cq_size,
|
|
&(*cq)->cq_physical,
|
|
&(*cq)->map);
|
|
MLX_FATAL_CHECK_STATUS(status, cq_map_err,
|
|
"cq map error");
|
|
|
|
status = nodnic_port_cq_dbr_dma_init(port_priv,cq);
|
|
|
|
/* update cq address */
|
|
#define NODIC_CQ_ADDR_HIGH 0x68
|
|
#define NODIC_CQ_ADDR_LOW 0x6c
|
|
address = (mlx_uint64)(*cq)->cq_physical;
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_low,
|
|
(mlx_uint32)(address) >> 12);
|
|
MLX_FATAL_CHECK_STATUS(status, dma_set_addr_low_err,
|
|
"cq set addr low error");
|
|
address = address >> 32;
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_high,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, dma_set_addr_high_err,
|
|
"cq set addr high error");
|
|
return status;
|
|
dma_set_addr_high_err:
|
|
dma_set_addr_low_err:
|
|
mlx_memory_ummap_dma(device_priv->utils, (*cq)->map);
|
|
cq_map_err:
|
|
mlx_memory_free_dma(device_priv->utils, (*cq)->cq_size,
|
|
(void **)&((*cq)->cq_virt));
|
|
dma_alloc_err:
|
|
mlx_memory_free(device_priv->utils, (void **)cq);
|
|
alloc_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_destroy_cq(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN nodnic_cq *cq
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL || cq == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
device_priv = port_priv->device;
|
|
|
|
if ( device_priv->device_cap.support_bar_cq_ctrl ){
|
|
status = mlx_memory_ummap_dma(device_priv->utils,
|
|
cq->arm_cq_doorbell.map);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
|
|
}
|
|
|
|
status = mlx_memory_free_dma(device_priv->utils,
|
|
sizeof(nodnic_arm_cq_db),
|
|
(void **)&(port_priv->arm_cq_doorbell_record));
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
|
|
}
|
|
}
|
|
|
|
mlx_memory_ummap_dma(device_priv->utils, cq->map);
|
|
|
|
mlx_memory_free_dma(device_priv->utils, cq->cq_size,
|
|
(void **)&(cq->cq_virt));
|
|
|
|
mlx_memory_free(device_priv->utils, (void **)&cq);
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_allocate_ring_db_dma (
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *nodnic_ring,
|
|
IN struct nodnic_doorbell *nodnic_db
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
|
|
if( port_priv == NULL || nodnic_ring == NULL || nodnic_db == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
#define NODNIC_RING_DBR_ADDR_LOW_OFFSET 0x1C
|
|
#define NODNIC_RING_DBR_ADDR_HIGH_OFFSET 0x18
|
|
status = nodnic_port_allocate_dbr_dma ( port_priv,nodnic_db,
|
|
nodnic_ring->offset + NODNIC_RING_DBR_ADDR_LOW_OFFSET,
|
|
nodnic_ring->offset + NODNIC_RING_DBR_ADDR_HIGH_OFFSET,
|
|
(void **)&nodnic_db->qp_doorbell_record,
|
|
sizeof(nodnic_qp_db),
|
|
(void **)&nodnic_ring->map );
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
|
|
"failed to allocate doorbell record dma");
|
|
|
|
return status;
|
|
alloc_dbr_dma_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_rx_pi_dma_alloc(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT nodnic_qp **qp
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL || qp == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
|
|
if ( ! device_priv->device_cap.support_rx_pi_dma ) {
|
|
goto rx_pi_dma_unsupported;
|
|
}
|
|
|
|
if ( device_priv->device_cap.support_rx_pi_dma ) {
|
|
status = nodnic_port_allocate_ring_db_dma(port_priv,
|
|
&(*qp)->receive.nodnic_ring,&(*qp)->receive.nodnic_ring.recv_doorbell);
|
|
MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
|
|
"rx doorbell dma allocation error");
|
|
}
|
|
|
|
return status;
|
|
|
|
dma_alloc_err:
|
|
rx_pi_dma_unsupported:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_send_db_dma(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *ring,
|
|
IN mlx_uint16 index
|
|
)
|
|
{
|
|
mlx_uint32 swapped = 0;
|
|
mlx_uint32 index32 = index;
|
|
mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
|
|
ring->send_doorbell.qp_doorbell_record->send_db = swapped;
|
|
|
|
return MLX_SUCCESS;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_tx_dbr_dma_init(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT nodnic_qp **qp
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL || qp == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
|
|
if ( ! device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset ) {
|
|
status = MLX_UNSUPPORTED;
|
|
goto uar_tx_db_unsupported;
|
|
}
|
|
status = nodnic_port_allocate_ring_db_dma(port_priv,
|
|
&(*qp)->send.nodnic_ring,&(*qp)->send.nodnic_ring.send_doorbell);
|
|
MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
|
|
"tx doorbell dma allocation error");
|
|
port_priv->send_doorbell = nodnic_port_send_db_dma;
|
|
|
|
return status;
|
|
|
|
dma_alloc_err:
|
|
uar_tx_db_unsupported:
|
|
invalid_parm:
|
|
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_create_qp(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN nodnic_queue_pair_type type,
|
|
IN mlx_size send_wq_size,
|
|
IN mlx_uint32 send_wqe_num,
|
|
IN mlx_size receive_wq_size,
|
|
IN mlx_uint32 recv_wqe_num,
|
|
OUT nodnic_qp **qp
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
mlx_uint32 max_ring_size = 0;
|
|
mlx_uint64 address = 0;
|
|
mlx_uint32 log_size = 0;
|
|
if( port_priv == NULL || qp == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
max_ring_size = (1 << device_priv->device_cap.log_max_ring_size);
|
|
if( send_wq_size > max_ring_size ||
|
|
receive_wq_size > max_ring_size ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
status = mlx_memory_zalloc(device_priv->utils,
|
|
sizeof(nodnic_qp),(mlx_void **)qp);
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_err,
|
|
"qp allocation error");
|
|
|
|
if( nodnic_qp_data_teable[type].send_offset == 0 ||
|
|
nodnic_qp_data_teable[type].recv_offset == 0){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_type;
|
|
}
|
|
|
|
(*qp)->send.nodnic_ring.offset = port_priv->port_offset +
|
|
nodnic_qp_data_teable[type].send_offset;
|
|
(*qp)->receive.nodnic_ring.offset = port_priv->port_offset +
|
|
nodnic_qp_data_teable[type].recv_offset;
|
|
|
|
status = mlx_memory_alloc_dma(device_priv->utils,
|
|
send_wq_size, NODNIC_MEMORY_ALIGN,
|
|
(void*)&(*qp)->send.wqe_virt);
|
|
MLX_FATAL_CHECK_STATUS(status, send_alloc_err,
|
|
"send wq allocation error");
|
|
|
|
status = mlx_memory_alloc_dma(device_priv->utils,
|
|
receive_wq_size, NODNIC_MEMORY_ALIGN,
|
|
&(*qp)->receive.wqe_virt);
|
|
MLX_FATAL_CHECK_STATUS(status, receive_alloc_err,
|
|
"receive wq allocation error");
|
|
|
|
status = mlx_memory_map_dma(device_priv->utils,
|
|
(*qp)->send.wqe_virt,
|
|
send_wq_size,
|
|
&(*qp)->send.nodnic_ring.wqe_physical,
|
|
&(*qp)->send.nodnic_ring.map);
|
|
MLX_FATAL_CHECK_STATUS(status, send_map_err,
|
|
"send wq map error");
|
|
|
|
status = mlx_memory_map_dma(device_priv->utils,
|
|
(*qp)->receive.wqe_virt,
|
|
receive_wq_size,
|
|
&(*qp)->receive.nodnic_ring.wqe_physical,
|
|
&(*qp)->receive.nodnic_ring.map);
|
|
MLX_FATAL_CHECK_STATUS(status, receive_map_err,
|
|
"receive wq map error");
|
|
|
|
status = nodnic_port_rx_pi_dma_alloc(port_priv,qp);
|
|
MLX_FATAL_CHECK_STATUS(status, rx_pi_dma_alloc_err,
|
|
"receive db dma error");
|
|
|
|
status = nodnic_port_tx_dbr_dma_init(port_priv,qp);
|
|
|
|
|
|
(*qp)->send.nodnic_ring.wq_size = send_wq_size;
|
|
(*qp)->send.nodnic_ring.num_wqes = send_wqe_num;
|
|
(*qp)->receive.nodnic_ring.wq_size = receive_wq_size;
|
|
(*qp)->receive.nodnic_ring.num_wqes = recv_wqe_num;
|
|
|
|
/* Set Ownership bit in Send/receive queue (0 - recv ; 1 - send) */
|
|
mlx_memory_set(device_priv->utils, (*qp)->send.wqe_virt, 0xff, send_wq_size );
|
|
mlx_memory_set(device_priv->utils, (*qp)->receive.wqe_virt, 0, recv_wqe_num );
|
|
|
|
/* update send ring */
|
|
#define NODIC_RING_QP_ADDR_HIGH 0x0
|
|
#define NODIC_RING_QP_ADDR_LOW 0x4
|
|
address = (mlx_uint64)(*qp)->send.nodnic_ring.wqe_physical;
|
|
status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
|
|
NODIC_RING_QP_ADDR_HIGH,
|
|
(mlx_uint32)(address >> 32));
|
|
MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
|
|
"send address write error 1");
|
|
mlx_utils_ilog2((*qp)->send.nodnic_ring.wq_size, &log_size);
|
|
address = address | log_size;
|
|
status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
|
|
NODIC_RING_QP_ADDR_LOW,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
|
|
"send address write error 2");
|
|
/* update receive ring */
|
|
address = (mlx_uint64)(*qp)->receive.nodnic_ring.wqe_physical;
|
|
status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
|
|
NODIC_RING_QP_ADDR_HIGH,
|
|
(mlx_uint32)(address >> 32));
|
|
MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
|
|
"receive address write error 1");
|
|
mlx_utils_ilog2((*qp)->receive.nodnic_ring.wq_size, &log_size);
|
|
address = address | log_size;
|
|
status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
|
|
NODIC_RING_QP_ADDR_LOW,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
|
|
"receive address write error 2");
|
|
|
|
return status;
|
|
write_recv_addr_err:
|
|
write_send_addr_err:
|
|
mlx_memory_ummap_dma(device_priv->utils, (*qp)->receive.nodnic_ring.map);
|
|
rx_pi_dma_alloc_err:
|
|
receive_map_err:
|
|
mlx_memory_ummap_dma(device_priv->utils, (*qp)->send.nodnic_ring.map);
|
|
send_map_err:
|
|
mlx_memory_free_dma(device_priv->utils, receive_wq_size,
|
|
&((*qp)->receive.wqe_virt));
|
|
receive_alloc_err:
|
|
mlx_memory_free_dma(device_priv->utils, send_wq_size,
|
|
(void **)&((*qp)->send.wqe_virt));
|
|
send_alloc_err:
|
|
invalid_type:
|
|
mlx_memory_free(device_priv->utils, (void **)qp);
|
|
alloc_err:
|
|
invalid_parm:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_destroy_qp(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN nodnic_queue_pair_type type __attribute__((unused)),
|
|
IN nodnic_qp *qp
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = port_priv->device;
|
|
|
|
status = mlx_memory_ummap_dma(device_priv->utils,
|
|
qp->receive.nodnic_ring.map);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
|
|
}
|
|
|
|
status = mlx_memory_ummap_dma(device_priv->utils, qp->send.nodnic_ring.map);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
|
|
}
|
|
|
|
if ( device_priv->device_cap.support_rx_pi_dma ){
|
|
status = mlx_memory_ummap_dma(device_priv->utils,
|
|
qp->receive.nodnic_ring.recv_doorbell.map);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
|
|
}
|
|
|
|
status = mlx_memory_free_dma(device_priv->utils,
|
|
sizeof(nodnic_qp_db),
|
|
(void **)&(qp->receive.nodnic_ring.recv_doorbell.qp_doorbell_record));
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
|
|
}
|
|
}
|
|
|
|
if ( device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset){
|
|
status = mlx_memory_ummap_dma(device_priv->utils,
|
|
qp->send.nodnic_ring.send_doorbell.map);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
|
|
}
|
|
|
|
status = mlx_memory_free_dma(device_priv->utils,
|
|
sizeof(nodnic_qp_db),
|
|
(void **)&(qp->send.nodnic_ring.send_doorbell.qp_doorbell_record));
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
|
|
}
|
|
}
|
|
|
|
status = mlx_memory_free_dma(device_priv->utils,
|
|
qp->receive.nodnic_ring.wq_size,
|
|
(void **)&(qp->receive.wqe_virt));
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
|
|
}
|
|
status = mlx_memory_free_dma(device_priv->utils,
|
|
qp->send.nodnic_ring.wq_size,
|
|
(void **)&(qp->send.wqe_virt));
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
|
|
}
|
|
status = mlx_memory_free(device_priv->utils, (void **)&qp);
|
|
if( status != MLX_SUCCESS){
|
|
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free failed (Status = %d)\n", status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_get_qpn(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *ring,
|
|
OUT mlx_uint32 *qpn
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 buffer = 0;
|
|
if( ring == NULL || qpn == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
if( ring->qpn != 0 ){
|
|
*qpn = ring->qpn;
|
|
goto success;
|
|
}
|
|
#define NODNIC_RING_QPN_OFFSET 0xc
|
|
#define NODNIC_RING_QPN_MASK 0xFFFFFF
|
|
status = nodnic_cmd_read(port_priv->device,
|
|
ring->offset + NODNIC_RING_QPN_OFFSET,
|
|
&buffer);
|
|
MLX_FATAL_CHECK_STATUS(status, read_err,
|
|
"nodnic_cmd_read failed");
|
|
ring->qpn = buffer & NODNIC_RING_QPN_MASK;
|
|
*qpn = ring->qpn;
|
|
read_err:
|
|
success:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
#ifdef DEVICE_CX3
|
|
static
|
|
mlx_status
|
|
nodnic_port_send_db_connectx3(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *ring __attribute__((unused)),
|
|
IN mlx_uint16 index
|
|
)
|
|
{
|
|
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
|
|
mlx_uint32 index32 = index;
|
|
mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
|
|
(mlx_uintn)&(ptr->send_doorbell), 1, &index32);
|
|
return MLX_SUCCESS;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_recv_db_connectx3(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *ring __attribute__((unused)),
|
|
IN mlx_uint16 index
|
|
)
|
|
{
|
|
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
|
|
mlx_uint32 index32 = index;
|
|
mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
|
|
(mlx_uintn)&(ptr->recv_doorbell), 1, &index32);
|
|
return MLX_SUCCESS;
|
|
}
|
|
#endif
|
|
static
|
|
mlx_status
|
|
nodnic_port_recv_db_dma(
|
|
IN nodnic_port_priv *port_priv __attribute__((unused)),
|
|
IN struct nodnic_ring *ring,
|
|
IN mlx_uint16 index
|
|
)
|
|
{
|
|
mlx_uint32 swapped = 0;
|
|
mlx_uint32 index32 = index;
|
|
mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
|
|
ring->recv_doorbell.qp_doorbell_record->recv_db = swapped;
|
|
return MLX_SUCCESS;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_update_ring_doorbell(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN struct nodnic_ring *ring,
|
|
IN mlx_uint16 index
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 buffer = 0;
|
|
if( ring == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
#define NODNIC_RING_RING_OFFSET 0x8
|
|
buffer = (mlx_uint32)((index & 0xFFFF)<< 8);
|
|
status = nodnic_cmd_write(port_priv->device,
|
|
ring->offset + NODNIC_RING_RING_OFFSET,
|
|
buffer);
|
|
MLX_CHECK_STATUS(port_priv->device, status, write_err,
|
|
"nodnic_cmd_write failed");
|
|
write_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_get_cq_size(
|
|
IN nodnic_port_priv *port_priv,
|
|
OUT mlx_uint64 *cq_size
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 out = 0;
|
|
status = nodnic_port_query(port_priv, nodnic_port_option_log_cq_size, &out);
|
|
MLX_FATAL_CHECK_STATUS(status, query_err,
|
|
"nodnic_port_query failed");
|
|
*cq_size = 1 << out;
|
|
query_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_allocate_eq(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_uint8 log_eq_size
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
mlx_uint64 address = 0;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
port_priv->eq.eq_size = ( ( 1 << log_eq_size ) * 1024 ); /* Size is in KB */
|
|
status = mlx_memory_alloc_dma(device_priv->utils,
|
|
port_priv->eq.eq_size,
|
|
NODNIC_MEMORY_ALIGN,
|
|
&port_priv->eq.eq_virt);
|
|
MLX_FATAL_CHECK_STATUS(status, alloc_err,
|
|
"eq allocation error");
|
|
|
|
status = mlx_memory_map_dma(device_priv->utils,
|
|
port_priv->eq.eq_virt,
|
|
port_priv->eq.eq_size,
|
|
&port_priv->eq.eq_physical,
|
|
&port_priv->eq.map);
|
|
MLX_FATAL_CHECK_STATUS(status, map_err,
|
|
"eq map error");
|
|
|
|
address = port_priv->eq.eq_physical;
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_low,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"failed to set eq addr low");
|
|
address = (address >> 32);
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_high,
|
|
(mlx_uint32)address);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"failed to set eq addr high");
|
|
return status;
|
|
set_err:
|
|
mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
|
|
map_err:
|
|
mlx_memory_free_dma(device_priv->utils,
|
|
port_priv->eq.eq_size,
|
|
(void **)&(port_priv->eq.eq_virt));
|
|
alloc_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
mlx_status
|
|
nodnic_port_free_eq(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device_priv = NULL;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
device_priv = port_priv->device;
|
|
mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
|
|
|
|
mlx_memory_free_dma(device_priv->utils,
|
|
port_priv->eq.eq_size,
|
|
(void **)&(port_priv->eq.eq_virt));
|
|
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_add_mac_filter(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_mac_address mac
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device= NULL;;
|
|
mlx_uint8 index = 0;
|
|
mlx_uint32 out = 0;
|
|
mlx_uint32 mac_filters_en = 0;
|
|
mlx_uint32 address = 0;
|
|
mlx_mac_address zero_mac;
|
|
mlx_utils *utils = NULL;
|
|
|
|
if( port_priv == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
device = port_priv->device;
|
|
utils = device->utils;
|
|
|
|
mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
|
|
/* check if mac already exists */
|
|
for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
|
|
mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
|
|
sizeof(mac), &out);
|
|
if ( out == 0 ){
|
|
status = MLX_FAILED;
|
|
goto already_exists;
|
|
}
|
|
}
|
|
|
|
/* serch for available mac filter slot */
|
|
for (index = 0 ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
|
|
mlx_memory_cmp(utils, &port_priv->mac_filters[index], &zero_mac,
|
|
sizeof(zero_mac), &out);
|
|
if ( out == 0 ){
|
|
break;
|
|
}
|
|
}
|
|
if ( index >= NODNIC_MAX_MAC_FILTERS ){
|
|
status = MLX_FAILED;
|
|
goto mac_list_full;
|
|
}
|
|
|
|
status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
|
|
&mac_filters_en);
|
|
MLX_CHECK_STATUS(device, status , query_err,
|
|
"nodnic_port_query failed");
|
|
if(mac_filters_en & (1 << index)){
|
|
status = MLX_FAILED;
|
|
goto mac_list_full;
|
|
}
|
|
port_priv->mac_filters[index] = mac;
|
|
|
|
// set mac filter
|
|
address = port_priv->port_offset + NODNIC_PORT_MAC_FILTERS_OFFSET +
|
|
(0x8 * index);
|
|
|
|
status = nodnic_cmd_write(device, address, mac.high );
|
|
MLX_CHECK_STATUS(device, status, write_err, "set mac high failed");
|
|
status = nodnic_cmd_write(device, address + 0x4, mac.low );
|
|
MLX_CHECK_STATUS(device, status, write_err, "set mac low failed");
|
|
|
|
// enable mac filter
|
|
mac_filters_en = mac_filters_en | (1 << index);
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
|
|
mac_filters_en);
|
|
MLX_CHECK_STATUS(device, status , set_err,
|
|
"nodnic_port_set failed");
|
|
set_err:
|
|
write_err:
|
|
query_err:
|
|
mac_list_full:
|
|
already_exists:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_remove_mac_filter(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_mac_address mac
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
nodnic_device_priv *device= NULL;;
|
|
mlx_uint8 index = 0;
|
|
mlx_uint32 out = 0;
|
|
mlx_uint32 mac_filters_en = 0;
|
|
mlx_mac_address zero_mac;
|
|
mlx_utils *utils = NULL;
|
|
|
|
if( port_priv == NULL){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
device = port_priv->device;
|
|
utils = device->utils;
|
|
|
|
mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
|
|
/* serch for mac filter */
|
|
for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
|
|
mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
|
|
sizeof(mac), &out);
|
|
if ( out == 0 ){
|
|
break;
|
|
}
|
|
}
|
|
if ( index == NODNIC_MAX_MAC_FILTERS ){
|
|
status = MLX_FAILED;
|
|
goto mac_not_found;
|
|
}
|
|
|
|
status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
|
|
&mac_filters_en);
|
|
MLX_CHECK_STATUS(device, status , query_err,
|
|
"nodnic_port_query failed");
|
|
if((mac_filters_en & (1 << index)) == 0){
|
|
status = MLX_FAILED;
|
|
goto mac_not_en;
|
|
}
|
|
port_priv->mac_filters[index] = zero_mac;
|
|
|
|
// disable mac filter
|
|
mac_filters_en = mac_filters_en & ~(1 << index);
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
|
|
mac_filters_en);
|
|
MLX_CHECK_STATUS(device, status , set_err,
|
|
"nodnic_port_set failed");
|
|
set_err:
|
|
query_err:
|
|
mac_not_en:
|
|
mac_not_found:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_set_network(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
/*mlx_uint32 network_valid = 0;
|
|
mlx_uint8 try = 0;*/
|
|
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_network_en, value);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_set failed");
|
|
port_priv->network_state = value;
|
|
set_err:
|
|
return status;
|
|
}
|
|
|
|
#ifdef DEVICE_CX3
|
|
static
|
|
mlx_status
|
|
nodnic_port_set_dma_connectx3(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
)
|
|
{
|
|
mlx_utils *utils = port_priv->device->utils;
|
|
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
|
|
mlx_uint32 data = (value ? 0xffffffff : 0x0);
|
|
mlx_pci_mem_write(utils, MlxPciWidthUint32, 0,
|
|
(mlx_uintn)&(ptr->dma_en), 1, &data);
|
|
return MLX_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_set_dma(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
)
|
|
{
|
|
return nodnic_port_set(port_priv, nodnic_port_option_dma_en, value);
|
|
}
|
|
|
|
static
|
|
mlx_status
|
|
nodnic_port_check_and_set_dma(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
if ( port_priv->dma_state == value ) {
|
|
MLX_DEBUG_WARN(port_priv->device,
|
|
"nodnic_port_check_and_set_dma: already %s\n",
|
|
(value ? "enabled" : "disabled"));
|
|
status = MLX_SUCCESS;
|
|
goto set_out;
|
|
}
|
|
|
|
status = port_priv->set_dma(port_priv, value);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_set failed");
|
|
port_priv->dma_state = value;
|
|
set_err:
|
|
set_out:
|
|
return status;
|
|
}
|
|
|
|
|
|
mlx_status
|
|
nodnic_port_set_promisc(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
){
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 buffer = value;
|
|
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_en, buffer);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_set failed");
|
|
set_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_set_promisc_multicast(
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_boolean value
|
|
){
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_uint32 buffer = value;
|
|
|
|
status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_multicast_en, buffer);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_set failed");
|
|
set_err:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_init(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
status = nodnic_port_set_network(port_priv, TRUE);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"nodnic_port_set_network failed");
|
|
set_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_close(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
status = nodnic_port_set_network(port_priv, FALSE);
|
|
MLX_FATAL_CHECK_STATUS(status, set_err,
|
|
"nodnic_port_set_network failed");
|
|
set_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_enable_dma(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
status = nodnic_port_check_and_set_dma(port_priv, TRUE);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_check_and_set_dma failed");
|
|
set_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_disable_dma(
|
|
IN nodnic_port_priv *port_priv
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
|
|
if( port_priv == NULL ){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto bad_param;
|
|
}
|
|
|
|
status = nodnic_port_check_and_set_dma(port_priv, FALSE);
|
|
MLX_CHECK_STATUS(port_priv->device, status, set_err,
|
|
"nodnic_port_check_and_set_dma failed");
|
|
set_err:
|
|
bad_param:
|
|
return status;
|
|
}
|
|
|
|
mlx_status
|
|
nodnic_port_thin_init(
|
|
IN nodnic_device_priv *device_priv,
|
|
IN nodnic_port_priv *port_priv,
|
|
IN mlx_uint8 port_index
|
|
)
|
|
{
|
|
mlx_status status = MLX_SUCCESS;
|
|
mlx_boolean reset_needed = 0;
|
|
#ifdef DEVICE_CX3
|
|
mlx_uint32 offset;
|
|
#endif
|
|
|
|
if( device_priv == NULL || port_priv == NULL || port_index > 1){
|
|
status = MLX_INVALID_PARAMETER;
|
|
goto invalid_parm;
|
|
}
|
|
|
|
port_priv->device = device_priv;
|
|
|
|
port_priv->port_offset = device_priv->device_offset +
|
|
nodnic_port_offset_table[port_index];
|
|
|
|
port_priv->port_num = port_index + 1;
|
|
|
|
port_priv->send_doorbell = nodnic_port_update_ring_doorbell;
|
|
port_priv->recv_doorbell = nodnic_port_update_ring_doorbell;
|
|
port_priv->set_dma = nodnic_port_set_dma;
|
|
#ifdef DEVICE_CX3
|
|
if (device_priv->device_cap.crspace_doorbells) {
|
|
status = nodnic_cmd_read(device_priv, (port_priv->port_offset + 0x100),
|
|
&offset);
|
|
if (status != MLX_SUCCESS) {
|
|
return status;
|
|
} else {
|
|
port_priv->data_flow_gw = (nodnic_port_data_flow_gw *)
|
|
(device_priv->utils->config + offset);
|
|
}
|
|
if ( nodnic_port_set ( port_priv, nodnic_port_option_crspace_en, 1 ) ) {
|
|
return MLX_FAILED;
|
|
}
|
|
port_priv->send_doorbell = nodnic_port_send_db_connectx3;
|
|
port_priv->recv_doorbell = nodnic_port_recv_db_connectx3;
|
|
port_priv->set_dma = nodnic_port_set_dma_connectx3;
|
|
}
|
|
#endif
|
|
if ( device_priv->device_cap.support_rx_pi_dma ) {
|
|
port_priv->recv_doorbell = nodnic_port_recv_db_dma;
|
|
}
|
|
|
|
/* clear reset_needed */
|
|
nodnic_port_read_reset_needed(port_priv, &reset_needed);
|
|
|
|
port_priv->port_type = NODNIC_PORT_TYPE_UNKNOWN;
|
|
invalid_parm:
|
|
return status;
|
|
}
|