/* The TDF_CTL masks are a superset of the RNI_RBP ones. So we can *usethemwhensettingeithertheTDE_CTForRNI_RBPregisters.
*/
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 *with64==0.Thereforewecaneitherdivideby64inthe *caseofconstants,orjustsubtract6fromthelog2ofthevalue *inordertogetthevaluewewillbeprogrammingintothe *registers.
*/
readrq = ilog2(fbd->readrq) - 6; if (readrq > 3)
override_1k = true;
readrq = clamp(readrq, 0, 3);
/* Be aggressive on the timings. We will have the interrupt *thresholdtimertickonceevery1usecandcoalescewritesfor *upto80usecs.
*/
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 *1usecandcoalescewritesforupto2usecs.
*/
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));
}
for (i = 0; i < 8; i++) { unsignedint size = fifo_config[i].size;
/* If we are coming up on a system that already has the *Rxdatapathenabledwedon'tneedtoreconfigurethe *FIFOs.Insteadwecanchecktoverifythevaluesare *largeenoughtomeetourneeds,andusethevaluesto *populatetheflowcontrol,ECN,anddropthresholds.
*/ 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 *granularitywhilethepacketbufferbaseaddressis *only64Bgranularity
*/
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 *basedonRXB_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 *1roomforonefulljumboframebeforesettingECN
*/
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 *interfacesforconfiguringpause.
*/
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));
/* 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, *bitsshouldresetthemselvesbackto1iflinkistrulyup
*/
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);
return0;
}
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);
}
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.