/* The TDF_CTL masks are a superset of the RNI_RBP ones. So we can * use them when setting either the TDE_CTF or RNI_RBP registers.
*/
val &= FBNIC_QM_TNI_TDF_CTL_MAX_OT | FBNIC_QM_TNI_TDF_CTL_MAX_OB;
val |= FIELD_PREP(FBNIC_QM_TNI_TDF_CTL_MRRS, readrq) |
FIELD_PREP(FBNIC_QM_TNI_TDF_CTL_CLS, cls);
/* All of the values are based on being a power of 2 starting * with 64 == 0. Therefore we can either divide by 64 in the * case of constants, or just subtract 6 from the log2 of the value * in order to get the value we will be programming into the * registers.
*/
readrq = ilog2(fbd->readrq) - 6; if (readrq > 3)
override_1k = true;
readrq = clamp(readrq, 0, 3);
/* Limit EDT to INT_MAX as this is the limit of the EDT Qdisc */
wr32(fbd, FBNIC_QM_TQS_EDT_TS_RANGE, INT_MAX);
/* Configure MTU * Due to known HW issue we cannot set the MTU to within 16 octets * of a 64 octet aligned boundary. So we will set the TQS_MTU(s) to * MTU + 1.
*/
wr32(fbd, FBNIC_QM_TQS_MTU_CTL0, FBNIC_MAX_JUMBO_FRAME_SIZE + 1);
wr32(fbd, FBNIC_QM_TQS_MTU_CTL1,
FIELD_PREP(FBNIC_QM_TQS_MTU_CTL1_BULK,
FBNIC_MAX_JUMBO_FRAME_SIZE + 1));
clock_freq = FBNIC_CLOCK_FREQ;
/* Be aggressive on the timings. We will have the interrupt * threshold timer tick once every 1 usec and coalesce writes for * up to 80 usecs.
*/
wr32(fbd, FBNIC_QM_TCQ_CTL0,
FIELD_PREP(FBNIC_QM_TCQ_CTL0_TICK_CYCLES,
clock_freq / 1000000) |
FIELD_PREP(FBNIC_QM_TCQ_CTL0_COAL_WAIT,
clock_freq / 12500));
/* We will have the interrupt threshold timer tick once every * 1 usec and coalesce writes for up to 2 usecs.
*/
wr32(fbd, FBNIC_QM_RCQ_CTL0,
FIELD_PREP(FBNIC_QM_RCQ_CTL0_TICK_CYCLES,
clock_freq / 1000000) |
FIELD_PREP(FBNIC_QM_RCQ_CTL0_COAL_WAIT,
clock_freq / 500000));
/* Configure spacer control to 64 beats. */
wr32(fbd, FBNIC_FAB_AXI4_AR_SPACER_2_CFG,
FBNIC_FAB_AXI4_AR_SPACER_MASK |
FIELD_PREP(FBNIC_FAB_AXI4_AR_SPACER_THREADSHOLD, 2));
}
/* Rx FIFO Configuration * The table consists of 8 entries, of which only 4 are currently used * The starting addr is in units of 64B and the size is in 2KB units * Below is the human readable version of the table defined below: * Function Addr Size * ---------------------------------- * Network to Host/BMC 384K 64K * Unused * Unused * Network to BMC 448K 32K * Network to Host 0 384K * Unused * BMC to Host 480K 32K * Unused
*/ staticconststruct fbnic_fifo_config fifo_config[] = {
{ .addr = 0x1800, .size = 0x20 }, /* Network to Host/BMC */
{ }, /* Unused */
{ }, /* Unused */
{ .addr = 0x1c00, .size = 0x10 }, /* Network to BMC */
{ .addr = 0x0000, .size = 0xc0 }, /* Network to Host */
{ }, /* Unused */
{ .addr = 0x1e00, .size = 0x10 }, /* BMC to Host */
{ } /* Unused */
};
staticvoid fbnic_mac_init_rxb(struct fbnic_dev *fbd)
{ bool rx_enable; int i;
for (i = 0; i < 8; i++) { unsignedint size = fifo_config[i].size;
/* If we are coming up on a system that already has the * Rx data path enabled we don't need to reconfigure the * FIFOs. Instead we can check to verify the values are * large enough to meet our needs, and use the values to * populate the flow control, ECN, and drop thresholds.
*/ if (rx_enable) {
size = FIELD_GET(FBNIC_RXB_PBUF_SIZE,
rd32(fbd, FBNIC_RXB_PBUF_CFG(i))); if (size < fifo_config[i].size)
dev_warn(fbd->dev, "fifo%d size of %d smaller than expected value of %d\n",
i, size << 11,
fifo_config[i].size << 11);
} else { /* Program RXB Cuthrough */
wr32(fbd, FBNIC_RXB_CT_SIZE(i),
FIELD_PREP(FBNIC_RXB_CT_SIZE_HEADER, 4) |
FIELD_PREP(FBNIC_RXB_CT_SIZE_PAYLOAD, 2));
/* The granularity for the packet buffer size is 2KB * granularity while the packet buffer base address is * only 64B granularity
*/
wr32(fbd, FBNIC_RXB_PBUF_CFG(i),
FIELD_PREP(FBNIC_RXB_PBUF_BASE_ADDR,
fifo_config[i].addr) |
FIELD_PREP(FBNIC_RXB_PBUF_SIZE, size));
/* The granularity for the credits is 64B. This is * based on RXB_PBUF_SIZE * 32 + 4.
*/
wr32(fbd, FBNIC_RXB_PBUF_CREDIT(i),
FIELD_PREP(FBNIC_RXB_PBUF_CREDIT_MASK,
size ? size * 32 + 4 : 0));
}
if (!size) continue;
/* Pause is size of FIFO with 56KB skid to start/stop */
wr32(fbd, FBNIC_RXB_PAUSE_THLD(i),
!(FBNIC_PAUSE_EN_MASK & (1u << i)) ? 0x1fff :
FIELD_PREP(FBNIC_RXB_PAUSE_THLD_ON,
size * 32 - 0x380) |
FIELD_PREP(FBNIC_RXB_PAUSE_THLD_OFF, 0x380));
/* Enable Drop when only one packet is left in the FIFO */
wr32(fbd, FBNIC_RXB_DROP_THLD(i),
!(FBNIC_DROP_EN_MASK & (1u << i)) ? 0x1fff :
FIELD_PREP(FBNIC_RXB_DROP_THLD_ON,
size * 32 -
FBNIC_MAX_JUMBO_FRAME_SIZE / 64) |
FIELD_PREP(FBNIC_RXB_DROP_THLD_OFF,
size * 32 -
FBNIC_MAX_JUMBO_FRAME_SIZE / 64));
/* Enable ECN bit when 1/4 of RXB is filled with at least * 1 room for one full jumbo frame before setting ECN
*/
wr32(fbd, FBNIC_RXB_ECN_THLD(i),
!(FBNIC_ECN_EN_MASK & (1u << i)) ? 0x1fff :
FIELD_PREP(FBNIC_RXB_ECN_THLD_ON,
max_t(unsignedint,
size * 32 / 4,
FBNIC_MAX_JUMBO_FRAME_SIZE / 64)) |
FIELD_PREP(FBNIC_RXB_ECN_THLD_OFF,
max_t(unsignedint,
size * 32 / 4,
FBNIC_MAX_JUMBO_FRAME_SIZE / 64)));
}
/* For now only enable drop and ECN. We need to add driver/kernel * interfaces for configuring pause.
*/
wr32(fbd, FBNIC_RXB_PAUSE_DROP_CTRL,
FIELD_PREP(FBNIC_RXB_PAUSE_DROP_CTRL_DROP_ENABLE,
FBNIC_DROP_EN_MASK) |
FIELD_PREP(FBNIC_RXB_PAUSE_DROP_CTRL_ECN_ENABLE,
FBNIC_ECN_EN_MASK));
/* Split the credits for the DRR up as follows: * Quantum0: 8000 Network to Host * Quantum1: 0 Not used * Quantum2: 80 BMC to Host * Quantum3: 0 Not used * Quantum4: 8000 Multicast to Host and BMC
*/
wr32(fbd, FBNIC_RXB_DWRR_RDE_WEIGHT0,
FIELD_PREP(FBNIC_RXB_DWRR_RDE_WEIGHT0_QUANTUM0, 0x40) |
FIELD_PREP(FBNIC_RXB_DWRR_RDE_WEIGHT0_QUANTUM2, 0x50));
wr32(fbd, FBNIC_RXB_DWRR_RDE_WEIGHT0_EXT,
FIELD_PREP(FBNIC_RXB_DWRR_RDE_WEIGHT0_QUANTUM0, 0x1f));
wr32(fbd, FBNIC_RXB_DWRR_RDE_WEIGHT1,
FIELD_PREP(FBNIC_RXB_DWRR_RDE_WEIGHT1_QUANTUM4, 0x40));
wr32(fbd, FBNIC_RXB_DWRR_RDE_WEIGHT1_EXT,
FIELD_PREP(FBNIC_RXB_DWRR_RDE_WEIGHT1_QUANTUM4, 0x1f));
/* Conservative configuration on MAC interface Start of Packet * protection FIFO. This sets the minimum depth of the FIFO before * we start sending packets to the MAC measured in 64B units and * up to 160 entries deep. * * For the ASIC the clock is fast enough that we will likely fill * the SOP FIFO before the MAC can drain it. So just use a minimum * value of 8.
*/
wr32(fbd, FBNIC_TMI_SOP_PROT_CTRL, 8);
/* Disable pause frames if not enabled */ if (!tx_pause)
command_config |= FBNIC_MAC_COMMAND_CONFIG_TX_PAUSE_DIS; if (!rx_pause)
command_config |= FBNIC_MAC_COMMAND_CONFIG_RX_PAUSE_DIS;
/* Disable fault handling if no FEC is requested */ if (fbn->fec == FBNIC_FEC_OFF)
command_config |= FBNIC_MAC_COMMAND_CONFIG_FLT_HDL_DIS;
pcs_status = rd32(fbd, FBNIC_SIG_PCS_OUT0); if (!(pcs_status & FBNIC_SIG_PCS_OUT0_LINK)) returnfalse;
/* Define the expected lane mask for the status bits we need to check */ switch (fbn->aui) { case FBNIC_AUI_100GAUI2:
lane_mask = 0xf; break; case FBNIC_AUI_50GAUI1:
lane_mask = 3; break; case FBNIC_AUI_LAUI2: switch (fbn->fec) { case FBNIC_FEC_OFF:
lane_mask = 0x63; break; case FBNIC_FEC_RS:
lane_mask = 5; break; case FBNIC_FEC_BASER:
lane_mask = 0xf; break;
} break; case FBNIC_AUI_25GAUI:
lane_mask = 1; break;
}
/* Use an XOR to remove the bits we expect to see set */ switch (fbn->fec) { case FBNIC_FEC_OFF:
lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK,
pcs_status); break; case FBNIC_FEC_RS:
lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_AMPS_LOCK,
pcs_status); break; case FBNIC_FEC_BASER:
lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT1_FCFEC_LOCK,
rd32(fbd, FBNIC_SIG_PCS_OUT1)); break;
}
/* If all lanes cancelled then we have a lock on all lanes */ return !lane_mask;
}
/* Flush status bits to clear possible stale data, * bits should reset themselves back to 1 if link is truly up
*/
wr32(fbd, FBNIC_SIG_PCS_OUT0, FBNIC_SIG_PCS_OUT0_LINK |
FBNIC_SIG_PCS_OUT0_BLOCK_LOCK |
FBNIC_SIG_PCS_OUT0_AMPS_LOCK);
wr32(fbd, FBNIC_SIG_PCS_OUT1, FBNIC_SIG_PCS_OUT1_FCFEC_LOCK);
wrfl(fbd);
/* Clear interrupt state due to recent changes. */
wr32(fbd, FBNIC_SIG_PCS_INTR_STS,
FBNIC_SIG_PCS_INTR_LINK_DOWN | FBNIC_SIG_PCS_INTR_LINK_UP);
link = fbnic_mac_get_pcs_link_status(fbd);
/* Enable interrupt to only capture changes in link state */
wr32(fbd, FBNIC_SIG_PCS_INTR_MASK,
~FBNIC_SIG_PCS_INTR_LINK_DOWN & ~FBNIC_SIG_PCS_INTR_LINK_UP);
wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 1u << FBNIC_PCS_MSIX_ENTRY);
/* Update FEC first to reflect FW current mode */ switch (fbd->fw_cap.link_fec) { case FBNIC_FW_LINK_FEC_NONE:
*fec = FBNIC_FEC_OFF; break; case FBNIC_FW_LINK_FEC_RS: default:
*fec = FBNIC_FEC_RS; break; case FBNIC_FW_LINK_FEC_BASER:
*fec = FBNIC_FEC_BASER; break;
}
}
staticint fbnic_pcs_enable_asic(struct fbnic_dev *fbd)
{ /* Mask and clear the PCS interrupt, will be enabled by link handler */
wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0);
wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0);
return 0;
}
staticvoid fbnic_pcs_disable_asic(struct fbnic_dev *fbd)
{ /* Mask and clear the PCS interrupt */
wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0);
wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0);
}
/** * fbnic_mac_init - Assign a MAC type and initialize the fbnic device * @fbd: Device pointer to device to initialize * * Return: zero on success, negative on failure * * Initialize the MAC function pointers and initializes the MAC of * the device.
**/ int fbnic_mac_init(struct fbnic_dev *fbd)
{
fbd->mac = &fbnic_mac_asic;
fbd->mac->init_regs(fbd);
return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet)
¤
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.