1274 lines
36 KiB
C
1274 lines
36 KiB
C
/*
|
|
* Copyright (C) 2005 - 2008 ServerEngines
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation. The full GNU General
|
|
* Public License is included in this distribution in the file called COPYING.
|
|
*
|
|
* Contact Information:
|
|
* linux-drivers@serverengines.com
|
|
*
|
|
* ServerEngines
|
|
* 209 N. Fair Oaks Ave
|
|
* Sunnyvale, CA 94085
|
|
*/
|
|
#include <linux/if_ether.h>
|
|
#include "hwlib.h"
|
|
#include "bestatus.h"
|
|
|
|
/*
|
|
*---------------------------------------------------------
|
|
* Function: be_eth_sq_create_ex
|
|
* Creates an ethernet send ring - extended version with
|
|
* additional parameters.
|
|
* pfob -
|
|
* rd - ring address
|
|
* length_in_bytes -
|
|
* type - The type of ring to create.
|
|
* ulp - The requested ULP number for the ring.
|
|
* This should be zero based, i.e. 0,1,2. This must
|
|
* be valid NIC ULP based on the firmware config.
|
|
* All doorbells for this ring must be sent to
|
|
* this ULP. The first network ring allocated for
|
|
* each ULP are higher performance than subsequent rings.
|
|
* cq_object - cq object for completions
|
|
* ex_parameters - Additional parameters (that may increase in
|
|
* future revisions). These parameters are only used
|
|
* for certain ring types -- see
|
|
* struct be_eth_sq_parameters for details.
|
|
* eth_sq -
|
|
* return status - BE_SUCCESS (0) on success. Negative error code on failure.
|
|
*---------------------------------------------------------
|
|
*/
|
|
int
|
|
be_eth_sq_create_ex(struct be_function_object *pfob, struct ring_desc *rd,
|
|
u32 length, u32 type, u32 ulp, struct be_cq_object *cq_object,
|
|
struct be_eth_sq_parameters *ex_parameters,
|
|
struct be_ethsq_object *eth_sq)
|
|
{
|
|
struct FWCMD_COMMON_ETH_TX_CREATE *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
u32 n;
|
|
unsigned long irql;
|
|
|
|
ASSERT(rd);
|
|
ASSERT(eth_sq);
|
|
ASSERT(ex_parameters);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
memset(eth_sq, 0, sizeof(*eth_sq));
|
|
|
|
eth_sq->parent_function = pfob;
|
|
eth_sq->bid = 0xFFFFFFFF;
|
|
eth_sq->cq_object = cq_object;
|
|
|
|
/* Translate hwlib interface to arm interface. */
|
|
switch (type) {
|
|
case BE_ETH_TX_RING_TYPE_FORWARDING:
|
|
type = ETH_TX_RING_TYPE_FORWARDING;
|
|
break;
|
|
case BE_ETH_TX_RING_TYPE_STANDARD:
|
|
type = ETH_TX_RING_TYPE_STANDARD;
|
|
break;
|
|
case BE_ETH_TX_RING_TYPE_BOUND:
|
|
ASSERT(ex_parameters->port < 2);
|
|
type = ETH_TX_RING_TYPE_BOUND;
|
|
break;
|
|
default:
|
|
TRACE(DL_ERR, "Invalid eth tx ring type:%d", type);
|
|
return BE_NOT_OK;
|
|
break;
|
|
}
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
ASSERT(wrb);
|
|
TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
/* NIC must be supported by the current config. */
|
|
ASSERT(pfob->fw_config.nic_ulp_mask);
|
|
|
|
/*
|
|
* The ulp parameter must select a valid NIC ULP
|
|
* for the current config.
|
|
*/
|
|
ASSERT((1 << ulp) & pfob->fw_config.nic_ulp_mask);
|
|
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_TX_CREATE);
|
|
fwcmd->header.request.port_number = ex_parameters->port;
|
|
|
|
AMAP_SET_BITS_PTR(ETX_CONTEXT, pd_id,
|
|
&fwcmd->params.request.context, 0);
|
|
|
|
n = be_ring_length_to_encoding(length, sizeof(struct ETH_WRB_AMAP));
|
|
AMAP_SET_BITS_PTR(ETX_CONTEXT, tx_ring_size,
|
|
&fwcmd->params.request.context, n);
|
|
|
|
AMAP_SET_BITS_PTR(ETX_CONTEXT, cq_id_send,
|
|
&fwcmd->params.request.context, cq_object->cq_id);
|
|
|
|
n = pfob->pci_function_number;
|
|
AMAP_SET_BITS_PTR(ETX_CONTEXT, func, &fwcmd->params.request.context, n);
|
|
|
|
fwcmd->params.request.type = type;
|
|
fwcmd->params.request.ulp_num = (1 << ulp);
|
|
fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE);
|
|
ASSERT(PAGES_SPANNED(rd->va, rd->length) >=
|
|
fwcmd->params.request.num_pages);
|
|
|
|
/* Create a page list for the FWCMD. */
|
|
be_rd_to_pa_list(rd, fwcmd->params.request.pages,
|
|
ARRAY_SIZE(fwcmd->params.request.pages));
|
|
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
if (status != BE_SUCCESS) {
|
|
TRACE(DL_ERR, "MCC to create etx queue failed.");
|
|
goto Error;
|
|
}
|
|
/* save the butler ID */
|
|
eth_sq->bid = fwcmd->params.response.cid;
|
|
|
|
/* add a reference to the corresponding CQ */
|
|
atomic_inc(&cq_object->ref_count);
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
This routine destroys an ethernet send queue
|
|
|
|
EthSq - EthSq Handle returned from EthSqCreate
|
|
|
|
This function always return BE_SUCCESS.
|
|
|
|
This function frees memory allocated by EthSqCreate for the EthSq Object.
|
|
|
|
*/
|
|
int be_eth_sq_destroy(struct be_ethsq_object *eth_sq)
|
|
{
|
|
int status = 0;
|
|
|
|
/* Send fwcmd to destroy the queue. */
|
|
status = be_function_ring_destroy(eth_sq->parent_function, eth_sq->bid,
|
|
FWCMD_RING_TYPE_ETH_TX, NULL, NULL, NULL, NULL);
|
|
ASSERT(status == 0);
|
|
|
|
/* Derefence any associated CQs. */
|
|
atomic_dec(ð_sq->cq_object->ref_count);
|
|
return status;
|
|
}
|
|
/*
|
|
This routine attempts to set the transmit flow control parameters.
|
|
|
|
FunctionObject - Handle to a function object
|
|
|
|
txfc_enable - transmit flow control enable - true for
|
|
enable, false for disable
|
|
|
|
rxfc_enable - receive flow control enable - true for
|
|
enable, false for disable
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int error
|
|
code is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
|
|
This function always fails in non-privileged machine context.
|
|
*/
|
|
int
|
|
be_eth_set_flow_control(struct be_function_object *pfob,
|
|
bool txfc_enable, bool rxfc_enable)
|
|
{
|
|
struct FWCMD_COMMON_SET_FLOW_CONTROL *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FLOW_CONTROL);
|
|
|
|
fwcmd->params.request.rx_flow_control = rxfc_enable;
|
|
fwcmd->params.request.tx_flow_control = txfc_enable;
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "set flow control fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine attempts to get the transmit flow control parameters.
|
|
|
|
pfob - Handle to a function object
|
|
|
|
txfc_enable - transmit flow control enable - true for
|
|
enable, false for disable
|
|
|
|
rxfc_enable - receive flow control enable - true for enable,
|
|
false for disable
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int error code
|
|
is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
|
|
This function always fails in non-privileged machine context.
|
|
*/
|
|
int
|
|
be_eth_get_flow_control(struct be_function_object *pfob,
|
|
bool *txfc_enable, bool *rxfc_enable)
|
|
{
|
|
struct FWCMD_COMMON_GET_FLOW_CONTROL *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FLOW_CONTROL);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "get flow control fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
*txfc_enable = fwcmd->params.response.tx_flow_control;
|
|
*rxfc_enable = fwcmd->params.response.rx_flow_control;
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------
|
|
* Function: be_eth_set_qos
|
|
* This function sets the ethernet transmit Quality of Service (QoS)
|
|
* characteristics of BladeEngine for the domain. All ethernet
|
|
* transmit rings of the domain will evenly share the bandwidth.
|
|
* The exeception to sharing is the host primary (super) ethernet
|
|
* transmit ring as well as the host ethernet forwarding ring
|
|
* for missed offload data.
|
|
* pfob -
|
|
* max_bps - the maximum bits per second in units of
|
|
* 10 Mbps (valid 0-100)
|
|
* max_pps - the maximum packets per second in units
|
|
* of 1 Kpps (0 indicates no limit)
|
|
* return status - BE_SUCCESS (0) on success. Negative error code on failure.
|
|
*---------------------------------------------------------
|
|
*/
|
|
int
|
|
be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps)
|
|
{
|
|
struct FWCMD_COMMON_SET_QOS *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_QOS);
|
|
|
|
/* Set fields in fwcmd */
|
|
fwcmd->params.request.max_bits_per_second_NIC = max_bps;
|
|
fwcmd->params.request.max_packets_per_second_NIC = max_pps;
|
|
fwcmd->params.request.valid_flags = QOS_BITS_NIC | QOS_PKTS_NIC;
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0)
|
|
TRACE(DL_ERR, "network set qos fwcmd failed.");
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------
|
|
* Function: be_eth_get_qos
|
|
* This function retrieves the ethernet transmit Quality of Service (QoS)
|
|
* characteristics for the domain.
|
|
* max_bps - the maximum bits per second in units of
|
|
* 10 Mbps (valid 0-100)
|
|
* max_pps - the maximum packets per second in units of
|
|
* 1 Kpps (0 indicates no limit)
|
|
* return status - BE_SUCCESS (0) on success. Negative error code on failure.
|
|
*---------------------------------------------------------
|
|
*/
|
|
int
|
|
be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps)
|
|
{
|
|
struct FWCMD_COMMON_GET_QOS *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_QOS);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "network get qos fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
*max_bps = fwcmd->params.response.max_bits_per_second_NIC;
|
|
*max_pps = fwcmd->params.response.max_packets_per_second_NIC;
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------
|
|
* Function: be_eth_set_frame_size
|
|
* This function sets the ethernet maximum frame size. The previous
|
|
* values are returned.
|
|
* pfob -
|
|
* tx_frame_size - maximum transmit frame size in bytes
|
|
* rx_frame_size - maximum receive frame size in bytes
|
|
* return status - BE_SUCCESS (0) on success. Negative error code on failure.
|
|
*---------------------------------------------------------
|
|
*/
|
|
int
|
|
be_eth_set_frame_size(struct be_function_object *pfob,
|
|
u32 *tx_frame_size, u32 *rx_frame_size)
|
|
{
|
|
struct FWCMD_COMMON_SET_FRAME_SIZE *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FRAME_SIZE);
|
|
fwcmd->params.request.max_tx_frame_size = *tx_frame_size;
|
|
fwcmd->params.request.max_rx_frame_size = *rx_frame_size;
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "network set frame size fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
*tx_frame_size = fwcmd->params.response.chip_max_tx_frame_size;
|
|
*rx_frame_size = fwcmd->params.response.chip_max_rx_frame_size;
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
This routine creates a Ethernet receive ring.
|
|
|
|
pfob - handle to a function object
|
|
rq_base_va - base VA for the default receive ring. this must be
|
|
exactly 8K in length and continguous physical memory.
|
|
cq_object - handle to a previously created CQ to be associated
|
|
with the RQ.
|
|
pp_eth_rq - pointer to an opqaue handle where an eth
|
|
receive object is returned.
|
|
Returns BE_SUCCESS if successfull, , otherwise a useful
|
|
int error code is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
this function allocates a struct be_ethrq_object *object.
|
|
there must be no more than 1 of these per function object, unless the
|
|
function object supports RSS (is networking and on the host).
|
|
the rq_base_va must point to a buffer of exactly 8K.
|
|
the erx::host_cqid (or host_stor_cqid) register and erx::ring_page registers
|
|
will be updated as appropriate on return
|
|
*/
|
|
int
|
|
be_eth_rq_create(struct be_function_object *pfob,
|
|
struct ring_desc *rd, struct be_cq_object *cq_object,
|
|
struct be_cq_object *bcmc_cq_object,
|
|
struct be_ethrq_object *eth_rq)
|
|
{
|
|
int status = 0;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
struct FWCMD_COMMON_ETH_RX_CREATE *fwcmd = NULL;
|
|
unsigned long irql;
|
|
|
|
/* MPU will set the */
|
|
ASSERT(rd);
|
|
ASSERT(eth_rq);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
eth_rq->parent_function = pfob;
|
|
eth_rq->cq_object = cq_object;
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_RX_CREATE);
|
|
|
|
fwcmd->params.request.num_pages = 2; /* required length */
|
|
fwcmd->params.request.cq_id = cq_object->cq_id;
|
|
|
|
if (bcmc_cq_object)
|
|
fwcmd->params.request.bcmc_cq_id = bcmc_cq_object->cq_id;
|
|
else
|
|
fwcmd->params.request.bcmc_cq_id = 0xFFFF;
|
|
|
|
/* Create a page list for the FWCMD. */
|
|
be_rd_to_pa_list(rd, fwcmd->params.request.pages,
|
|
ARRAY_SIZE(fwcmd->params.request.pages));
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
if (status != BE_SUCCESS) {
|
|
TRACE(DL_ERR, "fwcmd to map eth rxq frags failed.");
|
|
goto Error;
|
|
}
|
|
/* Save the ring ID for cleanup. */
|
|
eth_rq->rid = fwcmd->params.response.id;
|
|
|
|
atomic_inc(&cq_object->ref_count);
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine destroys an Ethernet receive queue
|
|
|
|
eth_rq - ethernet receive queue handle returned from eth_rq_create
|
|
|
|
Returns BE_SUCCESS on success and an appropriate int on failure.
|
|
|
|
This function frees resourcs allocated by EthRqCreate.
|
|
The erx::host_cqid (or host_stor_cqid) register and erx::ring_page
|
|
registers will be updated as appropriate on return
|
|
IRQL: < DISPATCH_LEVEL
|
|
*/
|
|
|
|
static void be_eth_rq_destroy_internal_cb(void *context, int status,
|
|
struct MCC_WRB_AMAP *wrb)
|
|
{
|
|
struct be_ethrq_object *eth_rq = (struct be_ethrq_object *) context;
|
|
|
|
if (status != BE_SUCCESS) {
|
|
TRACE(DL_ERR, "Destroy eth rq failed in internal callback.\n");
|
|
} else {
|
|
/* Dereference any CQs associated with this queue. */
|
|
atomic_dec(ð_rq->cq_object->ref_count);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int be_eth_rq_destroy(struct be_ethrq_object *eth_rq)
|
|
{
|
|
int status = BE_SUCCESS;
|
|
|
|
/* Send fwcmd to destroy the RQ. */
|
|
status = be_function_ring_destroy(eth_rq->parent_function,
|
|
eth_rq->rid, FWCMD_RING_TYPE_ETH_RX, NULL, NULL,
|
|
be_eth_rq_destroy_internal_cb, eth_rq);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*---------------------------------------------------------------------------
|
|
* Function: be_eth_rq_destroy_options
|
|
* Destroys an ethernet receive ring with finer granularity options
|
|
* than the standard be_eth_rq_destroy() API function.
|
|
* eth_rq -
|
|
* flush - Set to 1 to flush the ring, set to 0 to bypass the flush
|
|
* cb - Callback function on completion
|
|
* cb_context - Callback context
|
|
* return status - BE_SUCCESS (0) on success. Negative error code on failure.
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush,
|
|
mcc_wrb_cqe_callback cb, void *cb_context)
|
|
{
|
|
struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = BE_SUCCESS;
|
|
struct be_function_object *pfob = NULL;
|
|
unsigned long irql;
|
|
|
|
pfob = eth_rq->parent_function;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
TRACE(DL_INFO, "Destroy eth_rq ring id:%d, flush:%d", eth_rq->rid,
|
|
flush);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
ASSERT(wrb);
|
|
TRACE(DL_ERR, "No free MCC WRBs in destroy eth_rq ring.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY);
|
|
|
|
fwcmd->params.request.id = eth_rq->rid;
|
|
fwcmd->params.request.ring_type = FWCMD_RING_TYPE_ETH_RX;
|
|
fwcmd->params.request.bypass_flush = ((0 == flush) ? 1 : 0);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context,
|
|
be_eth_rq_destroy_internal_cb, eth_rq, fwcmd, NULL);
|
|
|
|
if (status != BE_SUCCESS && status != BE_PENDING) {
|
|
TRACE(DL_ERR, "eth_rq ring destroy failed. id:%d, flush:%d",
|
|
eth_rq->rid, flush);
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine queries the frag size for erx.
|
|
|
|
pfob - handle to a function object
|
|
|
|
frag_size_bytes - erx frag size in bytes that is/was set.
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int error
|
|
code is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
|
|
*/
|
|
int
|
|
be_eth_rq_get_frag_size(struct be_function_object *pfob, u32 *frag_size_bytes)
|
|
{
|
|
struct FWCMD_ETH_GET_RX_FRAG_SIZE *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
ASSERT(frag_size_bytes);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
return BE_STATUS_NO_MCC_WRB;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_GET_RX_FRAG_SIZE);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "get frag size fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
*frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
|
|
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine attempts to set the frag size for erx. If the frag size is
|
|
already set, the attempt fails and the current frag size is returned.
|
|
|
|
pfob - Handle to a function object
|
|
|
|
frag_size - Erx frag size in bytes that is/was set.
|
|
|
|
current_frag_size_bytes - Pointer to location where currrent frag
|
|
is to be rturned
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int error
|
|
code is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
|
|
This function always fails in non-privileged machine context.
|
|
*/
|
|
int
|
|
be_eth_rq_set_frag_size(struct be_function_object *pfob,
|
|
u32 frag_size, u32 *frag_size_bytes)
|
|
{
|
|
struct FWCMD_ETH_SET_RX_FRAG_SIZE *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
unsigned long irql;
|
|
|
|
ASSERT(frag_size_bytes);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto error;
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_SET_RX_FRAG_SIZE);
|
|
|
|
ASSERT(frag_size >= 128 && frag_size <= 16 * 1024);
|
|
|
|
/* This is the log2 of the fragsize. This is not the exact
|
|
* ERX encoding. */
|
|
fwcmd->params.request.new_fragsize_log2 = __ilog2_u32(frag_size);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
|
|
NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status != 0) {
|
|
TRACE(DL_ERR, "set frag size fwcmd failed.");
|
|
goto error;
|
|
}
|
|
|
|
*frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
|
|
error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
This routine gets or sets a mac address for a domain
|
|
given the port and mac.
|
|
|
|
FunctionObject - Function object handle.
|
|
port1 - Set to TRUE if this function will set/get the Port 1
|
|
address. Only the host may set this to TRUE.
|
|
mac1 - Set to TRUE if this function will set/get the
|
|
MAC 1 address. Only the host may set this to TRUE.
|
|
write - Set to TRUE if this function should write the mac address.
|
|
mac_address - Buffer of the mac address to read or write.
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
*/
|
|
int be_rxf_mac_address_read_write(struct be_function_object *pfob,
|
|
bool port1, /* VM must always set to false */
|
|
bool mac1, /* VM must always set to false */
|
|
bool mgmt, bool write,
|
|
bool permanent, u8 *mac_address,
|
|
mcc_wrb_cqe_callback cb, /* optional */
|
|
void *cb_context) /* optional */
|
|
{
|
|
int status = BE_SUCCESS;
|
|
union {
|
|
struct FWCMD_COMMON_NTWK_MAC_QUERY *query;
|
|
struct FWCMD_COMMON_NTWK_MAC_SET *set;
|
|
} fwcmd = {NULL};
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
u32 type = 0;
|
|
unsigned long irql;
|
|
struct be_mcc_wrb_response_copy rc;
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
ASSERT(mac_address);
|
|
|
|
ASSERT(port1 == false);
|
|
ASSERT(mac1 == false);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
TRACE(DL_ERR, "MCC wrb peek failed.");
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
|
|
if (mgmt) {
|
|
type = MAC_ADDRESS_TYPE_MANAGEMENT;
|
|
} else {
|
|
if (pfob->type == BE_FUNCTION_TYPE_NETWORK)
|
|
type = MAC_ADDRESS_TYPE_NETWORK;
|
|
else
|
|
type = MAC_ADDRESS_TYPE_STORAGE;
|
|
}
|
|
|
|
if (write) {
|
|
/* Prepares an embedded fwcmd, including
|
|
* request/response sizes.
|
|
*/
|
|
fwcmd.set = BE_PREPARE_EMBEDDED_FWCMD(pfob,
|
|
wrb, COMMON_NTWK_MAC_SET);
|
|
|
|
fwcmd.set->params.request.invalidate = 0;
|
|
fwcmd.set->params.request.mac1 = (mac1 ? 1 : 0);
|
|
fwcmd.set->params.request.port = (port1 ? 1 : 0);
|
|
fwcmd.set->params.request.type = type;
|
|
|
|
/* Copy the mac address to set. */
|
|
fwcmd.set->params.request.mac.SizeOfStructure =
|
|
sizeof(fwcmd.set->params.request.mac);
|
|
memcpy(fwcmd.set->params.request.mac.MACAddress,
|
|
mac_address, ETH_ALEN);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL,
|
|
cb, cb_context, NULL, NULL, fwcmd.set, NULL);
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Prepares an embedded fwcmd, including
|
|
* request/response sizes.
|
|
*/
|
|
fwcmd.query = BE_PREPARE_EMBEDDED_FWCMD(pfob,
|
|
wrb, COMMON_NTWK_MAC_QUERY);
|
|
|
|
fwcmd.query->params.request.mac1 = (mac1 ? 1 : 0);
|
|
fwcmd.query->params.request.port = (port1 ? 1 : 0);
|
|
fwcmd.query->params.request.type = type;
|
|
fwcmd.query->params.request.permanent = permanent;
|
|
|
|
rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_MAC_QUERY,
|
|
params.response.mac.MACAddress);
|
|
rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_MAC_QUERY,
|
|
params.response.mac.MACAddress);
|
|
rc.va = mac_address;
|
|
/* Post the f/w command (with a copy for the response) */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb,
|
|
cb_context, NULL, NULL, fwcmd.query, &rc);
|
|
}
|
|
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "mac set/query failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine writes data to context memory.
|
|
|
|
pfob - Function object handle.
|
|
mac_table - Set to the 128-bit multicast address hash table.
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
*/
|
|
|
|
int be_rxf_multicast_config(struct be_function_object *pfob,
|
|
bool promiscuous, u32 num, u8 *mac_table,
|
|
mcc_wrb_cqe_callback cb, /* optional */
|
|
void *cb_context,
|
|
struct be_multicast_q_ctxt *q_ctxt)
|
|
{
|
|
int status = BE_SUCCESS;
|
|
struct FWCMD_COMMON_NTWK_MULTICAST_SET *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
|
|
ASSERT(num <= ARRAY_SIZE(fwcmd->params.request.mac));
|
|
|
|
if (num > ARRAY_SIZE(fwcmd->params.request.mac)) {
|
|
TRACE(DL_ERR, "Too many multicast addresses. BE supports %d.",
|
|
(int) ARRAY_SIZE(fwcmd->params.request.mac));
|
|
return BE_NOT_OK;
|
|
}
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_MULTICAST_SET);
|
|
|
|
fwcmd->params.request.promiscuous = promiscuous;
|
|
if (!promiscuous) {
|
|
fwcmd->params.request.num_mac = num;
|
|
if (num > 0) {
|
|
ASSERT(mac_table);
|
|
memcpy(fwcmd->params.request.mac,
|
|
mac_table, ETH_ALEN * num);
|
|
}
|
|
}
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, fwcmd, NULL);
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "multicast fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This routine adds or removes a vlan tag from the rxf table.
|
|
|
|
FunctionObject - Function object handle.
|
|
VLanTag - VLan tag to add or remove.
|
|
Add - Set to TRUE if this will add a vlan tag
|
|
|
|
Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
|
|
|
|
IRQL: < DISPATCH_LEVEL
|
|
*/
|
|
int be_rxf_vlan_config(struct be_function_object *pfob,
|
|
bool promiscuous, u32 num, u16 *vlan_tag_array,
|
|
mcc_wrb_cqe_callback cb, /* optional */
|
|
void *cb_context,
|
|
struct be_vlan_q_ctxt *q_ctxt) /* optional */
|
|
{
|
|
int status = BE_SUCCESS;
|
|
struct FWCMD_COMMON_NTWK_VLAN_CONFIG *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
|
|
if (num > ARRAY_SIZE(fwcmd->params.request.vlan_tag)) {
|
|
TRACE(DL_ERR, "Too many VLAN tags.");
|
|
return BE_NOT_OK;
|
|
}
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_VLAN_CONFIG);
|
|
|
|
fwcmd->params.request.promiscuous = promiscuous;
|
|
if (!promiscuous) {
|
|
fwcmd->params.request.num_vlan = num;
|
|
|
|
if (num > 0) {
|
|
ASSERT(vlan_tag_array);
|
|
memcpy(fwcmd->params.request.vlan_tag, vlan_tag_array,
|
|
num * sizeof(vlan_tag_array[0]));
|
|
}
|
|
}
|
|
|
|
/* Post the commadn */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, fwcmd, NULL);
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "vlan fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
int be_rxf_link_status(struct be_function_object *pfob,
|
|
struct BE_LINK_STATUS *link_status,
|
|
mcc_wrb_cqe_callback cb,
|
|
void *cb_context,
|
|
struct be_link_status_q_ctxt *q_ctxt)
|
|
{
|
|
struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
struct be_mcc_wrb_response_copy rc;
|
|
|
|
ASSERT(link_status);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb,
|
|
COMMON_NTWK_LINK_STATUS_QUERY);
|
|
|
|
rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
|
|
params.response);
|
|
rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
|
|
params.response);
|
|
rc.va = link_status;
|
|
/* Post or queue the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, fwcmd, &rc);
|
|
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "link status fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
int
|
|
be_rxf_query_eth_statistics(struct be_function_object *pfob,
|
|
struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd,
|
|
u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb,
|
|
void *cb_context,
|
|
struct be_nonembedded_q_ctxt *q_ctxt)
|
|
{
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
|
|
ASSERT(va_for_fwcmd);
|
|
ASSERT(pa_for_fwcmd);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
TRACE(DL_INFO, "Query eth stats. fwcmd va:%p pa:0x%08x_%08x",
|
|
va_for_fwcmd, upper_32_bits(pa_for_fwcmd), (u32)pa_for_fwcmd);
|
|
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
va_for_fwcmd = BE_PREPARE_NONEMBEDDED_FWCMD(pfob, wrb,
|
|
va_for_fwcmd, pa_for_fwcmd, ETH_GET_STATISTICS);
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, va_for_fwcmd, NULL);
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "eth stats fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
int
|
|
be_rxf_promiscuous(struct be_function_object *pfob,
|
|
bool enable_port0, bool enable_port1,
|
|
mcc_wrb_cqe_callback cb, void *cb_context,
|
|
struct be_promiscuous_q_ctxt *q_ctxt)
|
|
{
|
|
struct FWCMD_ETH_PROMISCUOUS *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_PROMISCUOUS);
|
|
|
|
fwcmd->params.request.port0_promiscuous = enable_port0;
|
|
fwcmd->params.request.port1_promiscuous = enable_port1;
|
|
|
|
/* Post the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, fwcmd, NULL);
|
|
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "promiscuous fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
* Function: be_rxf_filter_config
|
|
* Configures BladeEngine ethernet receive filter settings.
|
|
* pfob -
|
|
* settings - Pointer to the requested filter settings.
|
|
* The response from BladeEngine will be placed back
|
|
* in this structure.
|
|
* cb - optional
|
|
* cb_context - optional
|
|
* q_ctxt - Optional. Pointer to a previously allocated struct.
|
|
* If the MCC WRB ring is full, this structure is
|
|
* used to queue the operation. It will be posted
|
|
* to the MCC ring when space becomes available. All
|
|
* queued commands will be posted to the ring in
|
|
* the order they are received. It is always valid
|
|
* to pass a pointer to a generic
|
|
* be_generic_q_ctxt. However, the specific
|
|
* context structs are generally smaller than
|
|
* the generic struct.
|
|
* return pend_status - BE_SUCCESS (0) on success.
|
|
* BE_PENDING (postive value) if the FWCMD
|
|
* completion is pending. Negative error code on failure.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
be_rxf_filter_config(struct be_function_object *pfob,
|
|
struct NTWK_RX_FILTER_SETTINGS *settings,
|
|
mcc_wrb_cqe_callback cb, void *cb_context,
|
|
struct be_rxf_filter_q_ctxt *q_ctxt)
|
|
{
|
|
struct FWCMD_COMMON_NTWK_RX_FILTER *fwcmd = NULL;
|
|
struct MCC_WRB_AMAP *wrb = NULL;
|
|
int status = 0;
|
|
struct be_generic_q_ctxt *generic_ctxt = NULL;
|
|
unsigned long irql;
|
|
struct be_mcc_wrb_response_copy rc;
|
|
|
|
ASSERT(settings);
|
|
|
|
spin_lock_irqsave(&pfob->post_lock, irql);
|
|
|
|
wrb = be_function_peek_mcc_wrb(pfob);
|
|
|
|
if (!wrb) {
|
|
if (q_ctxt && cb) {
|
|
wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
|
|
generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
|
|
generic_ctxt->context.bytes = sizeof(*q_ctxt);
|
|
} else {
|
|
status = BE_STATUS_NO_MCC_WRB;
|
|
goto Error;
|
|
}
|
|
}
|
|
/* Prepares an embedded fwcmd, including request/response sizes. */
|
|
fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_RX_FILTER);
|
|
memcpy(&fwcmd->params.request, settings, sizeof(*settings));
|
|
|
|
rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_RX_FILTER,
|
|
params.response);
|
|
rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_RX_FILTER,
|
|
params.response);
|
|
rc.va = settings;
|
|
/* Post or queue the f/w command */
|
|
status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
|
|
cb, cb_context, NULL, NULL, fwcmd, &rc);
|
|
|
|
if (status < 0) {
|
|
TRACE(DL_ERR, "RXF/ERX filter config fwcmd failed.");
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
spin_unlock_irqrestore(&pfob->post_lock, irql);
|
|
if (pfob->pend_queue_driving && pfob->mcc) {
|
|
pfob->pend_queue_driving = 0;
|
|
be_drive_mcc_wrb_queue(pfob->mcc);
|
|
}
|
|
return status;
|
|
}
|