// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <linux/bitfield.h>
#include <net/tcp.h>
#include "fbnic.h"
#include "fbnic_mac.h"
#include "fbnic_netdev.h"
static void fbnic_init_readrq(struct fbnic_dev *fbd, unsigned int offset,
unsigned int cls, unsigned int readrq)
{
u32 val = rd32(fbd, offset);
/* 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);
wr32(fbd, offset, val);
}
static void fbnic_init_mps(struct fbnic_dev *fbd, unsigned int offset,
unsigned int cls, unsigned int mps)
{
u32 val = rd32(fbd, offset);
/* Currently all MPS masks are identical so just use the first one */
val &= ~(FBNIC_QM_TNI_TCM_CTL_MPS | FBNIC_QM_TNI_TCM_CTL_CLS);
val |= FIELD_PREP(FBNIC_QM_TNI_TCM_CTL_MPS, mps) |
FIELD_PREP(FBNIC_QM_TNI_TCM_CTL_CLS, cls);
wr32(fbd, offset, val);
}
static void fbnic_mac_init_axi(struct fbnic_dev *fbd)
{
bool override_1k = false;
int readrq, mps, 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);
mps = ilog2(fbd->mps) - 6;
mps = clamp(mps, 0, 3);
cls = ilog2(L1_CACHE_BYTES) - 6;
cls = clamp(cls, 0, 3);
/* Configure Tx/Rx AXI Paths w/ Read Request and Max Payload sizes */
fbnic_init_readrq(fbd, FBNIC_QM_TNI_TDF_CTL, cls, readrq);
fbnic_init_mps(fbd, FBNIC_QM_TNI_TCM_CTL, cls, mps);
/* Configure QM TNI TDE:
* - Max outstanding AXI beats to 704(768 - 64) - guaranetees 8% of
* buffer capacity to descriptors.
* - Max outstanding transactions to 128
*/
wr32(fbd, FBNIC_QM_TNI_TDE_CTL,
FIELD_PREP(FBNIC_QM_TNI_TDE_CTL_MRRS_1K, override_1k ? 1 : 0) |
FIELD_PREP(FBNIC_QM_TNI_TDE_CTL_MAX_OB, 704) |
FIELD_PREP(FBNIC_QM_TNI_TDE_CTL_MAX_OT, 128) |
FIELD_PREP(FBNIC_QM_TNI_TDE_CTL_MRRS, readrq) |
FIELD_PREP(FBNIC_QM_TNI_TDE_CTL_CLS, cls));
fbnic_init_readrq(fbd, FBNIC_QM_RNI_RBP_CTL, cls, readrq);
fbnic_init_mps(fbd, FBNIC_QM_RNI_RDE_CTL, cls, mps);
fbnic_init_mps(fbd, FBNIC_QM_RNI_RCM_CTL, cls, mps);
}
static void fbnic_mac_init_qm(struct fbnic_dev *fbd)
{
u64 default_meta = FIELD_PREP(FBNIC_TWD_L2_HLEN_MASK, ETH_HLEN) |
FBNIC_TWD_FLAG_REQ_COMPLETION;
u32 clock_freq;
/* Configure default TWQ Metadata descriptor */
wr32(fbd, FBNIC_QM_TWQ_DEFAULT_META_L,
lower_32_bits(default_meta));
wr32(fbd, FBNIC_QM_TWQ_DEFAULT_META_H,
upper_32_bits(default_meta));
/* Configure TSO behavior */
wr32(fbd, FBNIC_QM_TQS_CTL0,
FIELD_PREP(FBNIC_QM_TQS_CTL0_LSO_TS_MASK,
FBNIC_QM_TQS_CTL0_LSO_TS_LAST) |
FIELD_PREP(FBNIC_QM_TQS_CTL0_PREFETCH_THRESH,
FBNIC_QM_TQS_CTL0_PREFETCH_THRESH_MIN));
/* 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,