brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · f526721 Raw
336 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip Sparx5 Switch driver3 *4 * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.5 */6 7#include "sparx5_main_regs.h"8#include "sparx5_main.h"9 10struct sparx5_sdlb_group sdlb_groups[SPX5_SDLB_GROUP_CNT] = {11	{ SPX5_SDLB_GROUP_RATE_MAX,    8192 / 1, 64 }, /*  25 G */12	{ 15000000000ULL,              8192 / 1, 64 }, /*  15 G */13	{ 10000000000ULL,              8192 / 1, 64 }, /*  10 G */14	{  5000000000ULL,              8192 / 1, 64 }, /*   5 G */15	{  2500000000ULL,              8192 / 1, 64 }, /* 2.5 G */16	{  1000000000ULL,              8192 / 2, 64 }, /*   1 G */17	{   500000000ULL,              8192 / 2, 64 }, /* 500 M */18	{   100000000ULL,              8192 / 4, 64 }, /* 100 M */19	{    50000000ULL,              8192 / 4, 64 }, /*  50 M */20	{     5000000ULL,              8192 / 8, 64 }  /*   5 M */21};22 23int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5)24{25	u32 clk_per_100ps;26	u64 clk_hz;27 28	clk_per_100ps = HSCH_SYS_CLK_PER_100PS_GET(spx5_rd(sparx5,29							   HSCH_SYS_CLK_PER));30	if (!clk_per_100ps)31		clk_per_100ps = SPX5_CLK_PER_100PS_DEFAULT;32 33	clk_hz = (10 * 1000 * 1000) / clk_per_100ps;34	return clk_hz *= 1000;35}36 37static int sparx5_sdlb_pup_interval_get(struct sparx5 *sparx5, u32 max_token,38					u64 max_rate)39{40	u64 clk_hz;41 42	clk_hz = sparx5_sdlb_clk_hz_get(sparx5);43 44	return div64_u64((8 * clk_hz * max_token), max_rate);45}46 47int sparx5_sdlb_pup_token_get(struct sparx5 *sparx5, u32 pup_interval, u64 rate)48{49	u64 clk_hz;50 51	if (!rate)52		return SPX5_SDLB_PUP_TOKEN_DISABLE;53 54	clk_hz = sparx5_sdlb_clk_hz_get(sparx5);55 56	return DIV64_U64_ROUND_UP((rate * pup_interval), (clk_hz * 8));57}58 59static void sparx5_sdlb_group_disable(struct sparx5 *sparx5, u32 group)60{61	spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(0),62		 ANA_AC_SDLB_PUP_CTRL_PUP_ENA, sparx5,63		 ANA_AC_SDLB_PUP_CTRL(group));64}65 66static void sparx5_sdlb_group_enable(struct sparx5 *sparx5, u32 group)67{68	spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(1),69		 ANA_AC_SDLB_PUP_CTRL_PUP_ENA, sparx5,70		 ANA_AC_SDLB_PUP_CTRL(group));71}72 73static u32 sparx5_sdlb_group_get_first(struct sparx5 *sparx5, u32 group)74{75	u32 val;76 77	val = spx5_rd(sparx5, ANA_AC_SDLB_XLB_START(group));78 79	return ANA_AC_SDLB_XLB_START_LBSET_START_GET(val);80}81 82static u32 sparx5_sdlb_group_get_next(struct sparx5 *sparx5, u32 group,83				      u32 lb)84{85	u32 val;86 87	val = spx5_rd(sparx5, ANA_AC_SDLB_XLB_NEXT(lb));88 89	return ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_GET(val);90}91 92static bool sparx5_sdlb_group_is_first(struct sparx5 *sparx5, u32 group,93				       u32 lb)94{95	return lb == sparx5_sdlb_group_get_first(sparx5, group);96}97 98static bool sparx5_sdlb_group_is_last(struct sparx5 *sparx5, u32 group,99				      u32 lb)100{101	return lb == sparx5_sdlb_group_get_next(sparx5, group, lb);102}103 104static bool sparx5_sdlb_group_is_empty(struct sparx5 *sparx5, u32 group)105{106	u32 val;107 108	val = spx5_rd(sparx5, ANA_AC_SDLB_PUP_CTRL(group));109 110	return ANA_AC_SDLB_PUP_CTRL_PUP_ENA_GET(val) == 0;111}112 113static u32 sparx5_sdlb_group_get_last(struct sparx5 *sparx5, u32 group)114{115	u32 itr, next;116 117	itr = sparx5_sdlb_group_get_first(sparx5, group);118 119	for (;;) {120		next = sparx5_sdlb_group_get_next(sparx5, group, itr);121		if (itr == next)122			return itr;123 124		itr = next;125	}126}127 128static bool sparx5_sdlb_group_is_singular(struct sparx5 *sparx5, u32 group)129{130	if (sparx5_sdlb_group_is_empty(sparx5, group))131		return false;132 133	return sparx5_sdlb_group_get_first(sparx5, group) ==134	       sparx5_sdlb_group_get_last(sparx5, group);135}136 137static int sparx5_sdlb_group_get_adjacent(struct sparx5 *sparx5, u32 group,138					  u32 idx, u32 *prev, u32 *next,139					  u32 *first)140{141	u32 itr;142 143	*first = sparx5_sdlb_group_get_first(sparx5, group);144	*prev = *first;145	*next = *first;146	itr = *first;147 148	for (;;) {149		*next = sparx5_sdlb_group_get_next(sparx5, group, itr);150 151		if (itr == idx)152			return 0; /* Found it */153 154		if (itr == *next)155			return -EINVAL; /* Was not found */156 157		*prev = itr;158		itr = *next;159	}160}161 162static int sparx5_sdlb_group_get_count(struct sparx5 *sparx5, u32 group)163{164	u32 itr, next;165	int count = 0;166 167	itr = sparx5_sdlb_group_get_first(sparx5, group);168 169	for (;;) {170		next = sparx5_sdlb_group_get_next(sparx5, group, itr);171		if (itr == next)172			return count;173 174		itr = next;175		count++;176	}177}178 179int sparx5_sdlb_group_get_by_rate(struct sparx5 *sparx5, u32 rate, u32 burst)180{181	const struct sparx5_sdlb_group *group;182	u64 rate_bps;183	int i, count;184 185	rate_bps = rate * 1000;186 187	for (i = SPX5_SDLB_GROUP_CNT - 1; i >= 0; i--) {188		group = &sdlb_groups[i];189 190		count = sparx5_sdlb_group_get_count(sparx5, i);191 192		/* Check that this group is not full.193		 * According to LB group configuration rules: the number of XLBs194		 * in a group must not exceed PUP_INTERVAL/4 - 1.195		 */196		if (count > ((group->pup_interval / 4) - 1))197			continue;198 199		if (rate_bps < group->max_rate)200			return i;201	}202 203	return -ENOSPC;204}205 206int sparx5_sdlb_group_get_by_index(struct sparx5 *sparx5, u32 idx, u32 *group)207{208	u32 itr, next;209	int i;210 211	for (i = 0; i < SPX5_SDLB_GROUP_CNT; i++) {212		if (sparx5_sdlb_group_is_empty(sparx5, i))213			continue;214 215		itr = sparx5_sdlb_group_get_first(sparx5, i);216 217		for (;;) {218			next = sparx5_sdlb_group_get_next(sparx5, i, itr);219 220			if (itr == idx) {221				*group = i;222				return 0; /* Found it */223			}224			if (itr == next)225				break; /* Was not found */226 227			itr = next;228		}229	}230 231	return -EINVAL;232}233 234static int sparx5_sdlb_group_link(struct sparx5 *sparx5, u32 group, u32 idx,235				  u32 first, u32 next, bool empty)236{237	/* Stop leaking */238	sparx5_sdlb_group_disable(sparx5, group);239 240	if (empty)241		return 0;242 243	/* Link insertion lb to next lb */244	spx5_wr(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_SET(next) |245			ANA_AC_SDLB_XLB_NEXT_LBGRP_SET(group),246		sparx5, ANA_AC_SDLB_XLB_NEXT(idx));247 248	/* Set the first lb */249	spx5_wr(ANA_AC_SDLB_XLB_START_LBSET_START_SET(first), sparx5,250		ANA_AC_SDLB_XLB_START(group));251 252	/* Start leaking */253	sparx5_sdlb_group_enable(sparx5, group);254 255	return 0;256};257 258int sparx5_sdlb_group_add(struct sparx5 *sparx5, u32 group, u32 idx)259{260	u32 first, next;261 262	/* We always add to head of the list */263	first = idx;264 265	if (sparx5_sdlb_group_is_empty(sparx5, group))266		next = idx;267	else268		next = sparx5_sdlb_group_get_first(sparx5, group);269 270	return sparx5_sdlb_group_link(sparx5, group, idx, first, next, false);271}272 273int sparx5_sdlb_group_del(struct sparx5 *sparx5, u32 group, u32 idx)274{275	u32 first, next, prev;276	bool empty = false;277 278	if (sparx5_sdlb_group_get_adjacent(sparx5, group, idx, &prev, &next,279					   &first) < 0) {280		pr_err("%s:%d Could not find idx: %d in group: %d", __func__,281		       __LINE__, idx, group);282		return -EINVAL;283	}284 285	if (sparx5_sdlb_group_is_singular(sparx5, group)) {286		empty = true;287	} else if (sparx5_sdlb_group_is_last(sparx5, group, idx)) {288		/* idx is removed, prev is now last */289		idx = prev;290		next = prev;291	} else if (sparx5_sdlb_group_is_first(sparx5, group, idx)) {292		/* idx is removed and points to itself, first is next */293		first = next;294		next = idx;295	} else {296		/* Next is not touched */297		idx = prev;298	}299 300	return sparx5_sdlb_group_link(sparx5, group, idx, first, next, empty);301}302 303void sparx5_sdlb_group_init(struct sparx5 *sparx5, u64 max_rate, u32 min_burst,304			    u32 frame_size, u32 idx)305{306	u32 thres_shift, mask = 0x01, power = 0;307	struct sparx5_sdlb_group *group;308	u64 max_token;309 310	group = &sdlb_groups[idx];311 312	/* Number of positions to right-shift LB's threshold value. */313	while ((min_burst & mask) == 0) {314		power++;315		mask <<= 1;316	}317	thres_shift = SPX5_SDLB_2CYCLES_TYPE2_THRES_OFFSET - power;318 319	max_token = (min_burst > SPX5_SDLB_PUP_TOKEN_MAX) ?320			    SPX5_SDLB_PUP_TOKEN_MAX :321			    min_burst;322	group->pup_interval =323		sparx5_sdlb_pup_interval_get(sparx5, max_token, max_rate);324 325	group->frame_size = frame_size;326 327	spx5_wr(ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL_SET(group->pup_interval),328		sparx5, ANA_AC_SDLB_PUP_INTERVAL(idx));329 330	spx5_wr(ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS_SET(frame_size),331		sparx5, ANA_AC_SDLB_FRM_RATE_TOKENS(idx));332 333	spx5_wr(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT_SET(thres_shift), sparx5,334		ANA_AC_SDLB_LBGRP_MISC(idx));335}336