/* bnx2x_init.h: Qlogic Everest network driver. * Structures and macroes needed during the initialization. * * Copyright (c) 2007-2013 Broadcom Corporation * Copyright (c) 2014 QLogic Corporation 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 as published by * the Free Software Foundation. * * Maintained by: Ariel Elior <ariel.elior@qlogic.com> * Written by: Eliezer Tamir * Modified by: Vladislav Zolotarov
*/
#ifndef BNX2X_INIT_H #define BNX2X_INIT_H
/* Init operation types and structures */ enum {
OP_RD = 0x1, /* read a single register */
OP_WR, /* write a single register */
OP_SW, /* copy a string to the device */
OP_ZR, /* clear memory */
OP_ZP, /* unzip then copy with DMAE */
OP_WR_64, /* write 64 bit pattern */
OP_WB, /* copy a string using DMAE */
OP_WB_ZR, /* Clear a string using DMAE or indirect-wr */ /* Skip the following ops if all of the init modes don't match */
OP_IF_MODE_OR, /* Skip the following ops if any of the init modes don't match */
OP_IF_MODE_AND,
OP_MAX
};
enum {
STAGE_START,
STAGE_END,
};
/* Returns the index of start or end of a specific block stage in ops array*/ #define BLOCK_OPS_IDX(block, stage, end) \
(2*(((block)*NUM_OF_INIT_PHASES) + (stage)) + (end))
/* structs for the various opcodes */ struct raw_op {
u32 op:8;
u32 offset:24;
u32 raw_data;
};
/* extracts the QM queue number for the specified port and vnic */ #define BNX2X_PF_Q_NUM(q_num, port, vnic)\
((((port) << 1) | (vnic)) * 16 + (q_num))
/* Maps the specified queue to the specified COS */ staticinlinevoid bnx2x_map_q_cos(struct bnx2x *bp, u32 q_num, u32 new_cos)
{ /* find current COS mapping */
u32 curr_cos = REG_RD(bp, QM_REG_QVOQIDX_0 + q_num * 4);
/* check if queue->COS mapping has changed */ if (curr_cos != new_cos) {
u32 num_vnics = BNX2X_PORT2_MODE_NUM_VNICS;
u32 reg_addr, reg_bit_map, vnic;
/* update parameters for 4port mode */ if (INIT_MODE_FLAGS(bp) & MODE_PORT4) {
num_vnics = BNX2X_PORT4_MODE_NUM_VNICS; if (BP_PORT(bp)) {
curr_cos += BNX2X_E3B0_PORT1_COS_OFFSET;
new_cos += BNX2X_E3B0_PORT1_COS_OFFSET;
}
}
/* clear queue bit from current COS bit map */
reg_addr = BNX2X_VOQ_Q_REG_ADDR(curr_cos, pf_q_num);
reg_bit_map = REG_RD(bp, reg_addr);
REG_WR(bp, reg_addr, reg_bit_map & (~q_bit_map));
/* set queue bit in new COS bit map */
reg_addr = BNX2X_VOQ_Q_REG_ADDR(new_cos, pf_q_num);
reg_bit_map = REG_RD(bp, reg_addr);
REG_WR(bp, reg_addr, reg_bit_map | q_bit_map);
/* set/clear queue bit in command-queue bit map * (E2/E3A0 only, valid COS values are 0/1)
*/ if (!(INIT_MODE_FLAGS(bp) & MODE_E3_B0)) {
reg_addr = BNX2X_Q_CMDQ_REG_ADDR(pf_q_num);
reg_bit_map = REG_RD(bp, reg_addr);
q_bit_map = 1 << (2 * (pf_q_num & 0xf));
reg_bit_map = new_cos ?
(reg_bit_map | q_bit_map) :
(reg_bit_map & (~q_bit_map));
REG_WR(bp, reg_addr, reg_bit_map);
}
}
}
}
/* Configures the QM according to the specified per-traffic-type COSes */ staticinlinevoid bnx2x_dcb_config_qm(struct bnx2x *bp, enum cos_mode mode, struct priority_cos *traffic_cos)
{
bnx2x_map_q_cos(bp, BNX2X_FCOE_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_FCOE].cos);
bnx2x_map_q_cos(bp, BNX2X_ISCSI_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos);
bnx2x_map_q_cos(bp, BNX2X_ISCSI_ACK_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos); if (mode != STATIC_COS) { /* required only in backward compatible COS mode */
bnx2x_map_q_cos(bp, BNX2X_ETH_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
bnx2x_map_q_cos(bp, BNX2X_TOE_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
bnx2x_map_q_cos(bp, BNX2X_TOE_ACK_Q,
traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos);
}
}
/* congestion management port init api description * the api works as follows: * the driver should pass the cmng_init_input struct, the port_init function * will prepare the required internal ram structure which will be passed back * to the driver (cmng_init) that will write it into the internal ram. * * IMPORTANT REMARKS: * 1. the cmng_init struct does not represent the contiguous internal ram * structure. the driver should use the XSTORM_CMNG_PERPORT_VARS_OFFSET * offset in order to write the port sub struct and the * PFID_FROM_PORT_AND_VNIC offset for writing the vnic sub struct (in other * words - don't use memcpy!). * 2. although the cmng_init struct is filled for the maximal vnic number * possible, the driver should only write the valid vnics into the internal * ram according to the appropriate port mode.
*/
/* CMNG constants, as derived from system spec calculations */
/* default MIN rate in case VNIC min rate is configured to zero- 100Mbps */ #define DEF_MIN_RATE 100
/* resolution of the rate shaping timer - 400 usec */ #define RS_PERIODIC_TIMEOUT_USEC 400
/* number of bytes in single QM arbitration cycle - * coefficient for calculating the fairness timer
*/ #define QM_ARB_BYTES 160000
/* resolution of Min algorithm 1:100 */ #define MIN_RES 100
/* how many bytes above threshold for * the minimal credit of Min algorithm
*/ #define MIN_ABOVE_THRESH 32768
/* Fairness algorithm integration time coefficient - * for calculating the actual Tfair
*/ #define T_FAIR_COEF ((MIN_ABOVE_THRESH + QM_ARB_BYTES) * 8 * MIN_RES)
/* this is the threshold below which no timer arming will occur. * 1.25 coefficient is for the threshold to be a little bigger * then the real time to compensate for timer in-accuracy
*/
pdata->rs_vars.rs_threshold =
(5 * RS_PERIODIC_TIMEOUT_USEC * r_param)/4;
/* rate shaping per-vnic variables */ for (vnic = 0; vnic < BNX2X_PORT2_MODE_NUM_VNICS; vnic++) { /* global vnic counter */
vdata->vnic_max_rate[vnic].vn_counter.rate =
input_data->vnic_max_rate[vnic]; /* maximal Mbps for this vnic * the quota in each timer period - number of bytes * transmitted in this period
*/
vdata->vnic_max_rate[vnic].vn_counter.quota =
RS_PERIODIC_TIMEOUT_USEC *
(u32)vdata->vnic_max_rate[vnic].vn_counter.rate / 8;
}
/* this is the resolution of the fairness timer */
fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
/* fairness per-port variables * for 10G it is 1000usec. for 1G it is 10000usec.
*/
tFair = T_FAIR_COEF / input_data->port_rate;
/* this is the threshold below which we won't arm the timer anymore */
pdata->fair_vars.fair_threshold = QM_ARB_BYTES;
/* we multiply by 1e3/8 to get bytes/msec. We don't want the credits * to pass a credit of the T_FAIR*FAIR_MEM (algorithm resolution)
*/
pdata->fair_vars.upper_bound = r_param * tFair * FAIR_MEM;
/* since each tick is 4 microSeconds */
pdata->fair_vars.fairness_timeout =
fair_periodic_timeout_usec / SDM_TICKS;
/* global vnic counter */ if (vnicWeightSum > 0) { /* fairness per-vnic variables */ for (vnic = 0; vnic < BNX2X_PORT2_MODE_NUM_VNICS; vnic++) { /* this is the credit for each period of the fairness * algorithm - number of bytes in T_FAIR (this vnic * share of the port rate)
*/
vdata->vnic_min_rate[vnic].vn_credit_delta =
(u32)input_data->vnic_min_rate[vnic] * 100 *
(T_FAIR_COEF / (8 * 100 * vnicWeightSum)); if (vdata->vnic_min_rate[vnic].vn_credit_delta <
pdata->fair_vars.fair_threshold +
MIN_ABOVE_THRESH) {
vdata->vnic_min_rate[vnic].vn_credit_delta =
pdata->fair_vars.fair_threshold +
MIN_ABOVE_THRESH;
}
}
}
}
for (cos = 0; cos < MAX_COS_NUMBER; cos++)
cosWeightSum += input_data->cos_min_rate[cos];
if (cosWeightSum > 0) {
for (vnic = 0; vnic < BNX2X_PORT2_MODE_NUM_VNICS; vnic++) { /* Since cos and vnic shouldn't work together the rate * to divide between the coses is the port rate.
*/
u32 *ccd = vdata->vnic_min_rate[vnic].cos_credit_delta; for (cos = 0; cos < MAX_COS_NUMBER; cos++) { /* this is the credit for each period of * the fairness algorithm - number of bytes * in T_FAIR (this cos share of the vnic rate)
*/
ccd[cos] =
(u32)input_data->cos_min_rate[cos] * 100 *
(T_FAIR_COEF / (8 * 100 * cosWeightSum)); if (ccd[cos] < pdata->fair_vars.fair_threshold
+ MIN_ABOVE_THRESH) {
ccd[cos] =
pdata->fair_vars.fair_threshold +
MIN_ABOVE_THRESH;
}
}
}
}
}
/* number of bytes transmitted in a rate of 10Gbps * in one usec = 1.25KB.
*/
r_param = BITS_TO_BYTES(input_data->port_rate);
bnx2x_init_max(input_data, r_param, ram_data);
bnx2x_init_min(input_data, r_param, ram_data);
bnx2x_init_fw_wrr(input_data, r_param, ram_data);
bnx2x_init_safc(input_data, ram_data);
}
/* Returns the index of start or end of a specific block stage in ops array */ #define BLOCK_OPS_IDX(block, stage, end) \
(2*(((block)*NUM_OF_INIT_PHASES) + (stage)) + (end))
#define INITOP_SET 0 /* set the HW directly */ #define INITOP_CLEAR 1 /* clear the HW directly */ #define INITOP_INIT 2 /* set the init-value array */
for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) {
u32 reg_mask = bnx2x_parity_reg_mask(bp, i);
if (reg_mask) {
reg_val = REG_RD(bp, bnx2x_blocks_parity_data[i].
sts_clr_addr); if (reg_val & reg_mask)
DP(NETIF_MSG_HW, "Parity errors in %s: 0x%x\n",
bnx2x_blocks_parity_data[i].name,
reg_val & reg_mask);
}
}
/* Check if there were parity attentions in MCP */
reg_val = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_MCP); if (reg_val & mcp_aeu_bits)
DP(NETIF_MSG_HW, "Parity error in MCP: 0x%x\n",
reg_val & mcp_aeu_bits);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.