xref: /linux/drivers/net/ethernet/microchip/lan966x/lan966x_taprio.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*e462b271SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
2*e462b271SHoratiu Vultur 
3*e462b271SHoratiu Vultur #include "lan966x_main.h"
4*e462b271SHoratiu Vultur 
5*e462b271SHoratiu Vultur #define LAN966X_TAPRIO_TIMEOUT_MS		1000
6*e462b271SHoratiu Vultur #define LAN966X_TAPRIO_ENTRIES_PER_PORT		2
7*e462b271SHoratiu Vultur 
8*e462b271SHoratiu Vultur /* Minimum supported cycle time in nanoseconds */
9*e462b271SHoratiu Vultur #define LAN966X_TAPRIO_MIN_CYCLE_TIME_NS	NSEC_PER_USEC
10*e462b271SHoratiu Vultur 
11*e462b271SHoratiu Vultur /* Maximum supported cycle time in nanoseconds */
12*e462b271SHoratiu Vultur #define LAN966X_TAPRIO_MAX_CYCLE_TIME_NS	(NSEC_PER_SEC - 1)
13*e462b271SHoratiu Vultur 
14*e462b271SHoratiu Vultur /* Total number of TAS GCL entries */
15*e462b271SHoratiu Vultur #define LAN966X_TAPRIO_NUM_GCL			256
16*e462b271SHoratiu Vultur 
17*e462b271SHoratiu Vultur /* TAPRIO link speeds for calculation of guard band */
18*e462b271SHoratiu Vultur enum lan966x_taprio_link_speed {
19*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_SPEED_NO_GB,
20*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_SPEED_10,
21*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_SPEED_100,
22*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_SPEED_1000,
23*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_SPEED_2500,
24*e462b271SHoratiu Vultur };
25*e462b271SHoratiu Vultur 
26*e462b271SHoratiu Vultur /* TAPRIO list states */
27*e462b271SHoratiu Vultur enum lan966x_taprio_state {
28*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_ADMIN,
29*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_ADVANCING,
30*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_PENDING,
31*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_OPERATING,
32*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_TERMINATING,
33*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_STATE_MAX,
34*e462b271SHoratiu Vultur };
35*e462b271SHoratiu Vultur 
36*e462b271SHoratiu Vultur /* TAPRIO GCL command */
37*e462b271SHoratiu Vultur enum lan966x_taprio_gcl_cmd {
38*e462b271SHoratiu Vultur 	LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES = 0,
39*e462b271SHoratiu Vultur };
40*e462b271SHoratiu Vultur 
lan966x_taprio_list_index(struct lan966x_port * port,u8 entry)41*e462b271SHoratiu Vultur static u32 lan966x_taprio_list_index(struct lan966x_port *port, u8 entry)
42*e462b271SHoratiu Vultur {
43*e462b271SHoratiu Vultur 	return port->chip_port * LAN966X_TAPRIO_ENTRIES_PER_PORT + entry;
44*e462b271SHoratiu Vultur }
45*e462b271SHoratiu Vultur 
lan966x_taprio_list_state_get(struct lan966x_port * port)46*e462b271SHoratiu Vultur static u32 lan966x_taprio_list_state_get(struct lan966x_port *port)
47*e462b271SHoratiu Vultur {
48*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
49*e462b271SHoratiu Vultur 	u32 val;
50*e462b271SHoratiu Vultur 
51*e462b271SHoratiu Vultur 	val = lan_rd(lan966x, QSYS_TAS_LST);
52*e462b271SHoratiu Vultur 	return QSYS_TAS_LST_LIST_STATE_GET(val);
53*e462b271SHoratiu Vultur }
54*e462b271SHoratiu Vultur 
lan966x_taprio_list_index_state_get(struct lan966x_port * port,u32 list)55*e462b271SHoratiu Vultur static u32 lan966x_taprio_list_index_state_get(struct lan966x_port *port,
56*e462b271SHoratiu Vultur 					       u32 list)
57*e462b271SHoratiu Vultur {
58*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
59*e462b271SHoratiu Vultur 
60*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list),
61*e462b271SHoratiu Vultur 		QSYS_TAS_CFG_CTRL_LIST_NUM,
62*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_CFG_CTRL);
63*e462b271SHoratiu Vultur 
64*e462b271SHoratiu Vultur 	return lan966x_taprio_list_state_get(port);
65*e462b271SHoratiu Vultur }
66*e462b271SHoratiu Vultur 
lan966x_taprio_list_state_set(struct lan966x_port * port,u32 state)67*e462b271SHoratiu Vultur static void lan966x_taprio_list_state_set(struct lan966x_port *port,
68*e462b271SHoratiu Vultur 					  u32 state)
69*e462b271SHoratiu Vultur {
70*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
71*e462b271SHoratiu Vultur 
72*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(state),
73*e462b271SHoratiu Vultur 		QSYS_TAS_LST_LIST_STATE,
74*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_LST);
75*e462b271SHoratiu Vultur }
76*e462b271SHoratiu Vultur 
lan966x_taprio_list_shutdown(struct lan966x_port * port,u32 list)77*e462b271SHoratiu Vultur static int lan966x_taprio_list_shutdown(struct lan966x_port *port,
78*e462b271SHoratiu Vultur 					u32 list)
79*e462b271SHoratiu Vultur {
80*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
81*e462b271SHoratiu Vultur 	bool pending, operating;
82*e462b271SHoratiu Vultur 	unsigned long end;
83*e462b271SHoratiu Vultur 	u32 state;
84*e462b271SHoratiu Vultur 
85*e462b271SHoratiu Vultur 	end = jiffies +  msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS);
86*e462b271SHoratiu Vultur 	/* It is required to try multiple times to set the state of list,
87*e462b271SHoratiu Vultur 	 * because the HW can overwrite this.
88*e462b271SHoratiu Vultur 	 */
89*e462b271SHoratiu Vultur 	do {
90*e462b271SHoratiu Vultur 		state = lan966x_taprio_list_state_get(port);
91*e462b271SHoratiu Vultur 
92*e462b271SHoratiu Vultur 		pending = false;
93*e462b271SHoratiu Vultur 		operating = false;
94*e462b271SHoratiu Vultur 
95*e462b271SHoratiu Vultur 		if (state == LAN966X_TAPRIO_STATE_ADVANCING ||
96*e462b271SHoratiu Vultur 		    state == LAN966X_TAPRIO_STATE_PENDING) {
97*e462b271SHoratiu Vultur 			lan966x_taprio_list_state_set(port,
98*e462b271SHoratiu Vultur 						      LAN966X_TAPRIO_STATE_ADMIN);
99*e462b271SHoratiu Vultur 			pending = true;
100*e462b271SHoratiu Vultur 		}
101*e462b271SHoratiu Vultur 
102*e462b271SHoratiu Vultur 		if (state == LAN966X_TAPRIO_STATE_OPERATING) {
103*e462b271SHoratiu Vultur 			lan966x_taprio_list_state_set(port,
104*e462b271SHoratiu Vultur 						      LAN966X_TAPRIO_STATE_TERMINATING);
105*e462b271SHoratiu Vultur 			operating = true;
106*e462b271SHoratiu Vultur 		}
107*e462b271SHoratiu Vultur 
108*e462b271SHoratiu Vultur 		/* If the entry was in pending and now gets in admin, then there
109*e462b271SHoratiu Vultur 		 * is nothing else to do, so just bail out
110*e462b271SHoratiu Vultur 		 */
111*e462b271SHoratiu Vultur 		state = lan966x_taprio_list_state_get(port);
112*e462b271SHoratiu Vultur 		if (pending &&
113*e462b271SHoratiu Vultur 		    state == LAN966X_TAPRIO_STATE_ADMIN)
114*e462b271SHoratiu Vultur 			return 0;
115*e462b271SHoratiu Vultur 
116*e462b271SHoratiu Vultur 		/* If the list was in operating and now is in terminating or
117*e462b271SHoratiu Vultur 		 * admin, then is OK to exit but it needs to wait until the list
118*e462b271SHoratiu Vultur 		 * will get in admin. It is not required to set the state
119*e462b271SHoratiu Vultur 		 * again.
120*e462b271SHoratiu Vultur 		 */
121*e462b271SHoratiu Vultur 		if (operating &&
122*e462b271SHoratiu Vultur 		    (state == LAN966X_TAPRIO_STATE_TERMINATING ||
123*e462b271SHoratiu Vultur 		     state == LAN966X_TAPRIO_STATE_ADMIN))
124*e462b271SHoratiu Vultur 			break;
125*e462b271SHoratiu Vultur 
126*e462b271SHoratiu Vultur 	} while (!time_after(jiffies, end));
127*e462b271SHoratiu Vultur 
128*e462b271SHoratiu Vultur 	end = jiffies + msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS);
129*e462b271SHoratiu Vultur 	do {
130*e462b271SHoratiu Vultur 		state = lan966x_taprio_list_state_get(port);
131*e462b271SHoratiu Vultur 		if (state == LAN966X_TAPRIO_STATE_ADMIN)
132*e462b271SHoratiu Vultur 			break;
133*e462b271SHoratiu Vultur 
134*e462b271SHoratiu Vultur 	} while (!time_after(jiffies, end));
135*e462b271SHoratiu Vultur 
136*e462b271SHoratiu Vultur 	/* If the list was in operating mode, it could be stopped while some
137*e462b271SHoratiu Vultur 	 * queues where closed, so make sure to restore "all-queues-open"
138*e462b271SHoratiu Vultur 	 */
139*e462b271SHoratiu Vultur 	if (operating) {
140*e462b271SHoratiu Vultur 		lan_wr(QSYS_TAS_GS_CTRL_HSCH_POS_SET(port->chip_port),
141*e462b271SHoratiu Vultur 		       lan966x, QSYS_TAS_GS_CTRL);
142*e462b271SHoratiu Vultur 
143*e462b271SHoratiu Vultur 		lan_wr(QSYS_TAS_GATE_STATE_TAS_GATE_STATE_SET(0xff),
144*e462b271SHoratiu Vultur 		       lan966x, QSYS_TAS_GATE_STATE);
145*e462b271SHoratiu Vultur 	}
146*e462b271SHoratiu Vultur 
147*e462b271SHoratiu Vultur 	return 0;
148*e462b271SHoratiu Vultur }
149*e462b271SHoratiu Vultur 
lan966x_taprio_shutdown(struct lan966x_port * port)150*e462b271SHoratiu Vultur static int lan966x_taprio_shutdown(struct lan966x_port *port)
151*e462b271SHoratiu Vultur {
152*e462b271SHoratiu Vultur 	u32 i, list, state;
153*e462b271SHoratiu Vultur 	int err;
154*e462b271SHoratiu Vultur 
155*e462b271SHoratiu Vultur 	for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
156*e462b271SHoratiu Vultur 		list = lan966x_taprio_list_index(port, i);
157*e462b271SHoratiu Vultur 		state = lan966x_taprio_list_index_state_get(port, list);
158*e462b271SHoratiu Vultur 		if (state == LAN966X_TAPRIO_STATE_ADMIN)
159*e462b271SHoratiu Vultur 			continue;
160*e462b271SHoratiu Vultur 
161*e462b271SHoratiu Vultur 		err = lan966x_taprio_list_shutdown(port, list);
162*e462b271SHoratiu Vultur 		if (err)
163*e462b271SHoratiu Vultur 			return err;
164*e462b271SHoratiu Vultur 	}
165*e462b271SHoratiu Vultur 
166*e462b271SHoratiu Vultur 	return 0;
167*e462b271SHoratiu Vultur }
168*e462b271SHoratiu Vultur 
169*e462b271SHoratiu Vultur /* Find a suitable list for a new schedule. First priority is a list in state
170*e462b271SHoratiu Vultur  * pending. Second priority is a list in state admin.
171*e462b271SHoratiu Vultur  */
lan966x_taprio_find_list(struct lan966x_port * port,struct tc_taprio_qopt_offload * qopt,int * new_list,int * obs_list)172*e462b271SHoratiu Vultur static int lan966x_taprio_find_list(struct lan966x_port *port,
173*e462b271SHoratiu Vultur 				    struct tc_taprio_qopt_offload *qopt,
174*e462b271SHoratiu Vultur 				    int *new_list, int *obs_list)
175*e462b271SHoratiu Vultur {
176*e462b271SHoratiu Vultur 	int state[LAN966X_TAPRIO_ENTRIES_PER_PORT];
177*e462b271SHoratiu Vultur 	int list[LAN966X_TAPRIO_ENTRIES_PER_PORT];
178*e462b271SHoratiu Vultur 	int err, oper = -1;
179*e462b271SHoratiu Vultur 	u32 i;
180*e462b271SHoratiu Vultur 
181*e462b271SHoratiu Vultur 	*new_list = -1;
182*e462b271SHoratiu Vultur 	*obs_list = -1;
183*e462b271SHoratiu Vultur 
184*e462b271SHoratiu Vultur 	/* If there is already an entry in operating mode, return this list in
185*e462b271SHoratiu Vultur 	 * obs_list, such that when the new list will get activated the
186*e462b271SHoratiu Vultur 	 * operating list will be stopped. In this way is possible to have
187*e462b271SHoratiu Vultur 	 * smooth transitions between the lists
188*e462b271SHoratiu Vultur 	 */
189*e462b271SHoratiu Vultur 	for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
190*e462b271SHoratiu Vultur 		list[i] = lan966x_taprio_list_index(port, i);
191*e462b271SHoratiu Vultur 		state[i] = lan966x_taprio_list_index_state_get(port, list[i]);
192*e462b271SHoratiu Vultur 		if (state[i] == LAN966X_TAPRIO_STATE_OPERATING)
193*e462b271SHoratiu Vultur 			oper = list[i];
194*e462b271SHoratiu Vultur 	}
195*e462b271SHoratiu Vultur 
196*e462b271SHoratiu Vultur 	for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
197*e462b271SHoratiu Vultur 		if (state[i] == LAN966X_TAPRIO_STATE_PENDING) {
198*e462b271SHoratiu Vultur 			err = lan966x_taprio_shutdown(port);
199*e462b271SHoratiu Vultur 			if (err)
200*e462b271SHoratiu Vultur 				return err;
201*e462b271SHoratiu Vultur 
202*e462b271SHoratiu Vultur 			*new_list = list[i];
203*e462b271SHoratiu Vultur 			*obs_list = (oper == -1) ? *new_list : oper;
204*e462b271SHoratiu Vultur 			return 0;
205*e462b271SHoratiu Vultur 		}
206*e462b271SHoratiu Vultur 	}
207*e462b271SHoratiu Vultur 
208*e462b271SHoratiu Vultur 	for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) {
209*e462b271SHoratiu Vultur 		if (state[i] == LAN966X_TAPRIO_STATE_ADMIN) {
210*e462b271SHoratiu Vultur 			*new_list = list[i];
211*e462b271SHoratiu Vultur 			*obs_list = (oper == -1) ? *new_list : oper;
212*e462b271SHoratiu Vultur 			return 0;
213*e462b271SHoratiu Vultur 		}
214*e462b271SHoratiu Vultur 	}
215*e462b271SHoratiu Vultur 
216*e462b271SHoratiu Vultur 	return -ENOSPC;
217*e462b271SHoratiu Vultur }
218*e462b271SHoratiu Vultur 
lan966x_taprio_check(struct tc_taprio_qopt_offload * qopt)219*e462b271SHoratiu Vultur static int lan966x_taprio_check(struct tc_taprio_qopt_offload *qopt)
220*e462b271SHoratiu Vultur {
221*e462b271SHoratiu Vultur 	u64 total_time = 0;
222*e462b271SHoratiu Vultur 	u32 i;
223*e462b271SHoratiu Vultur 
224*e462b271SHoratiu Vultur 	/* This is not supported by th HW */
225*e462b271SHoratiu Vultur 	if (qopt->cycle_time_extension)
226*e462b271SHoratiu Vultur 		return -EOPNOTSUPP;
227*e462b271SHoratiu Vultur 
228*e462b271SHoratiu Vultur 	/* There is a limited number of gcl entries that can be used, they are
229*e462b271SHoratiu Vultur 	 * shared by all ports
230*e462b271SHoratiu Vultur 	 */
231*e462b271SHoratiu Vultur 	if (qopt->num_entries > LAN966X_TAPRIO_NUM_GCL)
232*e462b271SHoratiu Vultur 		return -EINVAL;
233*e462b271SHoratiu Vultur 
234*e462b271SHoratiu Vultur 	/* Don't allow cycle times bigger than 1 sec or smaller than 1 usec */
235*e462b271SHoratiu Vultur 	if (qopt->cycle_time < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS ||
236*e462b271SHoratiu Vultur 	    qopt->cycle_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
237*e462b271SHoratiu Vultur 		return -EINVAL;
238*e462b271SHoratiu Vultur 
239*e462b271SHoratiu Vultur 	for (i = 0; i < qopt->num_entries; ++i) {
240*e462b271SHoratiu Vultur 		struct tc_taprio_sched_entry *entry = &qopt->entries[i];
241*e462b271SHoratiu Vultur 
242*e462b271SHoratiu Vultur 		/* Don't allow intervals bigger than 1 sec or smaller than 1
243*e462b271SHoratiu Vultur 		 * usec
244*e462b271SHoratiu Vultur 		 */
245*e462b271SHoratiu Vultur 		if (entry->interval < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS ||
246*e462b271SHoratiu Vultur 		    entry->interval > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
247*e462b271SHoratiu Vultur 			return -EINVAL;
248*e462b271SHoratiu Vultur 
249*e462b271SHoratiu Vultur 		if (qopt->entries[i].command != TC_TAPRIO_CMD_SET_GATES)
250*e462b271SHoratiu Vultur 			return -EINVAL;
251*e462b271SHoratiu Vultur 
252*e462b271SHoratiu Vultur 		total_time += qopt->entries[i].interval;
253*e462b271SHoratiu Vultur 	}
254*e462b271SHoratiu Vultur 
255*e462b271SHoratiu Vultur 	/* Don't allow the total time of intervals be bigger than 1 sec */
256*e462b271SHoratiu Vultur 	if (total_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS)
257*e462b271SHoratiu Vultur 		return -EINVAL;
258*e462b271SHoratiu Vultur 
259*e462b271SHoratiu Vultur 	/* The HW expects that the cycle time to be at least as big as sum of
260*e462b271SHoratiu Vultur 	 * each interval of gcl
261*e462b271SHoratiu Vultur 	 */
262*e462b271SHoratiu Vultur 	if (qopt->cycle_time < total_time)
263*e462b271SHoratiu Vultur 		return -EINVAL;
264*e462b271SHoratiu Vultur 
265*e462b271SHoratiu Vultur 	return 0;
266*e462b271SHoratiu Vultur }
267*e462b271SHoratiu Vultur 
lan966x_taprio_gcl_free_get(struct lan966x_port * port,unsigned long * free_list)268*e462b271SHoratiu Vultur static int lan966x_taprio_gcl_free_get(struct lan966x_port *port,
269*e462b271SHoratiu Vultur 				       unsigned long *free_list)
270*e462b271SHoratiu Vultur {
271*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
272*e462b271SHoratiu Vultur 	u32 num_free, state, list;
273*e462b271SHoratiu Vultur 	u32 base, next, max_list;
274*e462b271SHoratiu Vultur 
275*e462b271SHoratiu Vultur 	/* By default everything is free */
276*e462b271SHoratiu Vultur 	bitmap_fill(free_list, LAN966X_TAPRIO_NUM_GCL);
277*e462b271SHoratiu Vultur 	num_free = LAN966X_TAPRIO_NUM_GCL;
278*e462b271SHoratiu Vultur 
279*e462b271SHoratiu Vultur 	/* Iterate over all gcl entries and find out which are free. And mark
280*e462b271SHoratiu Vultur 	 * those that are not free.
281*e462b271SHoratiu Vultur 	 */
282*e462b271SHoratiu Vultur 	max_list = lan966x->num_phys_ports * LAN966X_TAPRIO_ENTRIES_PER_PORT;
283*e462b271SHoratiu Vultur 	for (list = 0; list < max_list; ++list) {
284*e462b271SHoratiu Vultur 		state = lan966x_taprio_list_index_state_get(port, list);
285*e462b271SHoratiu Vultur 		if (state == LAN966X_TAPRIO_STATE_ADMIN)
286*e462b271SHoratiu Vultur 			continue;
287*e462b271SHoratiu Vultur 
288*e462b271SHoratiu Vultur 		base = lan_rd(lan966x, QSYS_TAS_LIST_CFG);
289*e462b271SHoratiu Vultur 		base = QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_GET(base);
290*e462b271SHoratiu Vultur 		next = base;
291*e462b271SHoratiu Vultur 
292*e462b271SHoratiu Vultur 		do {
293*e462b271SHoratiu Vultur 			clear_bit(next, free_list);
294*e462b271SHoratiu Vultur 			num_free--;
295*e462b271SHoratiu Vultur 
296*e462b271SHoratiu Vultur 			lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next),
297*e462b271SHoratiu Vultur 				QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM,
298*e462b271SHoratiu Vultur 				lan966x, QSYS_TAS_CFG_CTRL);
299*e462b271SHoratiu Vultur 
300*e462b271SHoratiu Vultur 			next = lan_rd(lan966x, QSYS_TAS_GCL_CT_CFG2);
301*e462b271SHoratiu Vultur 			next = QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_GET(next);
302*e462b271SHoratiu Vultur 		} while (base != next);
303*e462b271SHoratiu Vultur 	}
304*e462b271SHoratiu Vultur 
305*e462b271SHoratiu Vultur 	return num_free;
306*e462b271SHoratiu Vultur }
307*e462b271SHoratiu Vultur 
lan966x_taprio_gcl_setup_entry(struct lan966x_port * port,struct tc_taprio_sched_entry * entry,u32 next_entry)308*e462b271SHoratiu Vultur static void lan966x_taprio_gcl_setup_entry(struct lan966x_port *port,
309*e462b271SHoratiu Vultur 					   struct tc_taprio_sched_entry *entry,
310*e462b271SHoratiu Vultur 					   u32 next_entry)
311*e462b271SHoratiu Vultur {
312*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
313*e462b271SHoratiu Vultur 
314*e462b271SHoratiu Vultur 	/* Setup a single gcl entry */
315*e462b271SHoratiu Vultur 	lan_wr(QSYS_TAS_GCL_CT_CFG_GATE_STATE_SET(entry->gate_mask) |
316*e462b271SHoratiu Vultur 	       QSYS_TAS_GCL_CT_CFG_HSCH_POS_SET(port->chip_port) |
317*e462b271SHoratiu Vultur 	       QSYS_TAS_GCL_CT_CFG_OP_TYPE_SET(LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES),
318*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_GCL_CT_CFG);
319*e462b271SHoratiu Vultur 
320*e462b271SHoratiu Vultur 	lan_wr(QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE_SET(port->chip_port) |
321*e462b271SHoratiu Vultur 	       QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_SET(next_entry),
322*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_GCL_CT_CFG2);
323*e462b271SHoratiu Vultur 
324*e462b271SHoratiu Vultur 	lan_wr(entry->interval, lan966x, QSYS_TAS_GCL_TM_CFG);
325*e462b271SHoratiu Vultur }
326*e462b271SHoratiu Vultur 
lan966x_taprio_gcl_setup(struct lan966x_port * port,struct tc_taprio_qopt_offload * qopt,int list)327*e462b271SHoratiu Vultur static int lan966x_taprio_gcl_setup(struct lan966x_port *port,
328*e462b271SHoratiu Vultur 				    struct tc_taprio_qopt_offload *qopt,
329*e462b271SHoratiu Vultur 				    int list)
330*e462b271SHoratiu Vultur {
331*e462b271SHoratiu Vultur 	DECLARE_BITMAP(free_list, LAN966X_TAPRIO_NUM_GCL);
332*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
333*e462b271SHoratiu Vultur 	u32 i, base, next;
334*e462b271SHoratiu Vultur 
335*e462b271SHoratiu Vultur 	if (lan966x_taprio_gcl_free_get(port, free_list) < qopt->num_entries)
336*e462b271SHoratiu Vultur 		return -ENOSPC;
337*e462b271SHoratiu Vultur 
338*e462b271SHoratiu Vultur 	/* Select list */
339*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list),
340*e462b271SHoratiu Vultur 		QSYS_TAS_CFG_CTRL_LIST_NUM,
341*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_CFG_CTRL);
342*e462b271SHoratiu Vultur 
343*e462b271SHoratiu Vultur 	/* Setup the address of the first gcl entry */
344*e462b271SHoratiu Vultur 	base = find_first_bit(free_list, LAN966X_TAPRIO_NUM_GCL);
345*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_SET(base),
346*e462b271SHoratiu Vultur 		QSYS_TAS_LIST_CFG_LIST_BASE_ADDR,
347*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_LIST_CFG);
348*e462b271SHoratiu Vultur 
349*e462b271SHoratiu Vultur 	/* Iterate over entries and add them to the gcl list */
350*e462b271SHoratiu Vultur 	next = base;
351*e462b271SHoratiu Vultur 	for (i = 0; i < qopt->num_entries; ++i) {
352*e462b271SHoratiu Vultur 		lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next),
353*e462b271SHoratiu Vultur 			QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM,
354*e462b271SHoratiu Vultur 			lan966x, QSYS_TAS_CFG_CTRL);
355*e462b271SHoratiu Vultur 
356*e462b271SHoratiu Vultur 		/* If the entry is last, point back to the start of the list */
357*e462b271SHoratiu Vultur 		if (i == qopt->num_entries - 1)
358*e462b271SHoratiu Vultur 			next = base;
359*e462b271SHoratiu Vultur 		else
360*e462b271SHoratiu Vultur 			next = find_next_bit(free_list, LAN966X_TAPRIO_NUM_GCL,
361*e462b271SHoratiu Vultur 					     next + 1);
362*e462b271SHoratiu Vultur 
363*e462b271SHoratiu Vultur 		lan966x_taprio_gcl_setup_entry(port, &qopt->entries[i], next);
364*e462b271SHoratiu Vultur 	}
365*e462b271SHoratiu Vultur 
366*e462b271SHoratiu Vultur 	return 0;
367*e462b271SHoratiu Vultur }
368*e462b271SHoratiu Vultur 
369*e462b271SHoratiu Vultur /* Calculate new base_time based on cycle_time. The HW recommends to have the
370*e462b271SHoratiu Vultur  * new base time at least 2 * cycle type + current time
371*e462b271SHoratiu Vultur  */
lan966x_taprio_new_base_time(struct lan966x * lan966x,const u32 cycle_time,const ktime_t org_base_time,ktime_t * new_base_time)372*e462b271SHoratiu Vultur static void lan966x_taprio_new_base_time(struct lan966x *lan966x,
373*e462b271SHoratiu Vultur 					 const u32 cycle_time,
374*e462b271SHoratiu Vultur 					 const ktime_t org_base_time,
375*e462b271SHoratiu Vultur 					 ktime_t *new_base_time)
376*e462b271SHoratiu Vultur {
377*e462b271SHoratiu Vultur 	ktime_t current_time, threshold_time;
378*e462b271SHoratiu Vultur 	struct timespec64 ts;
379*e462b271SHoratiu Vultur 
380*e462b271SHoratiu Vultur 	/* Get the current time and calculate the threshold_time */
381*e462b271SHoratiu Vultur 	lan966x_ptp_gettime64(&lan966x->phc[LAN966X_PHC_PORT].info, &ts);
382*e462b271SHoratiu Vultur 	current_time = timespec64_to_ktime(ts);
383*e462b271SHoratiu Vultur 	threshold_time = current_time + (2 * cycle_time);
384*e462b271SHoratiu Vultur 
385*e462b271SHoratiu Vultur 	/* If the org_base_time is in enough in future just use it */
386*e462b271SHoratiu Vultur 	if (org_base_time >= threshold_time) {
387*e462b271SHoratiu Vultur 		*new_base_time = org_base_time;
388*e462b271SHoratiu Vultur 		return;
389*e462b271SHoratiu Vultur 	}
390*e462b271SHoratiu Vultur 
391*e462b271SHoratiu Vultur 	/* If the org_base_time is smaller than current_time, calculate the new
392*e462b271SHoratiu Vultur 	 * base time as following.
393*e462b271SHoratiu Vultur 	 */
394*e462b271SHoratiu Vultur 	if (org_base_time <= current_time) {
395*e462b271SHoratiu Vultur 		u64 tmp = current_time - org_base_time;
396*e462b271SHoratiu Vultur 		u32 rem = 0;
397*e462b271SHoratiu Vultur 
398*e462b271SHoratiu Vultur 		if (tmp > cycle_time)
399*e462b271SHoratiu Vultur 			div_u64_rem(tmp, cycle_time, &rem);
400*e462b271SHoratiu Vultur 		rem = cycle_time - rem;
401*e462b271SHoratiu Vultur 		*new_base_time = threshold_time + rem;
402*e462b271SHoratiu Vultur 		return;
403*e462b271SHoratiu Vultur 	}
404*e462b271SHoratiu Vultur 
405*e462b271SHoratiu Vultur 	/* The only left place for org_base_time is between current_time and
406*e462b271SHoratiu Vultur 	 * threshold_time. In this case the new_base_time is calculated like
407*e462b271SHoratiu Vultur 	 * org_base_time + 2 * cycletime
408*e462b271SHoratiu Vultur 	 */
409*e462b271SHoratiu Vultur 	*new_base_time = org_base_time + 2 * cycle_time;
410*e462b271SHoratiu Vultur }
411*e462b271SHoratiu Vultur 
lan966x_taprio_speed_set(struct lan966x_port * port,int speed)412*e462b271SHoratiu Vultur int lan966x_taprio_speed_set(struct lan966x_port *port, int speed)
413*e462b271SHoratiu Vultur {
414*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
415*e462b271SHoratiu Vultur 	u8 taprio_speed;
416*e462b271SHoratiu Vultur 
417*e462b271SHoratiu Vultur 	switch (speed) {
418*e462b271SHoratiu Vultur 	case SPEED_10:
419*e462b271SHoratiu Vultur 		taprio_speed = LAN966X_TAPRIO_SPEED_10;
420*e462b271SHoratiu Vultur 		break;
421*e462b271SHoratiu Vultur 	case SPEED_100:
422*e462b271SHoratiu Vultur 		taprio_speed = LAN966X_TAPRIO_SPEED_100;
423*e462b271SHoratiu Vultur 		break;
424*e462b271SHoratiu Vultur 	case SPEED_1000:
425*e462b271SHoratiu Vultur 		taprio_speed = LAN966X_TAPRIO_SPEED_1000;
426*e462b271SHoratiu Vultur 		break;
427*e462b271SHoratiu Vultur 	case SPEED_2500:
428*e462b271SHoratiu Vultur 		taprio_speed = LAN966X_TAPRIO_SPEED_2500;
429*e462b271SHoratiu Vultur 		break;
430*e462b271SHoratiu Vultur 	default:
431*e462b271SHoratiu Vultur 		return -EINVAL;
432*e462b271SHoratiu Vultur 	}
433*e462b271SHoratiu Vultur 
434*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_PROFILE_CFG_LINK_SPEED_SET(taprio_speed),
435*e462b271SHoratiu Vultur 		QSYS_TAS_PROFILE_CFG_LINK_SPEED,
436*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_PROFILE_CFG(port->chip_port));
437*e462b271SHoratiu Vultur 
438*e462b271SHoratiu Vultur 	return 0;
439*e462b271SHoratiu Vultur }
440*e462b271SHoratiu Vultur 
lan966x_taprio_add(struct lan966x_port * port,struct tc_taprio_qopt_offload * qopt)441*e462b271SHoratiu Vultur int lan966x_taprio_add(struct lan966x_port *port,
442*e462b271SHoratiu Vultur 		       struct tc_taprio_qopt_offload *qopt)
443*e462b271SHoratiu Vultur {
444*e462b271SHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
445*e462b271SHoratiu Vultur 	int err, new_list, obs_list;
446*e462b271SHoratiu Vultur 	struct timespec64 ts;
447*e462b271SHoratiu Vultur 	ktime_t base_time;
448*e462b271SHoratiu Vultur 
449*e462b271SHoratiu Vultur 	err = lan966x_taprio_check(qopt);
450*e462b271SHoratiu Vultur 	if (err)
451*e462b271SHoratiu Vultur 		return err;
452*e462b271SHoratiu Vultur 
453*e462b271SHoratiu Vultur 	err = lan966x_taprio_find_list(port, qopt, &new_list, &obs_list);
454*e462b271SHoratiu Vultur 	if (err)
455*e462b271SHoratiu Vultur 		return err;
456*e462b271SHoratiu Vultur 
457*e462b271SHoratiu Vultur 	err = lan966x_taprio_gcl_setup(port, qopt, new_list);
458*e462b271SHoratiu Vultur 	if (err)
459*e462b271SHoratiu Vultur 		return err;
460*e462b271SHoratiu Vultur 
461*e462b271SHoratiu Vultur 	lan966x_taprio_new_base_time(lan966x, qopt->cycle_time,
462*e462b271SHoratiu Vultur 				     qopt->base_time, &base_time);
463*e462b271SHoratiu Vultur 
464*e462b271SHoratiu Vultur 	ts = ktime_to_timespec64(base_time);
465*e462b271SHoratiu Vultur 	lan_wr(QSYS_TAS_BT_NSEC_NSEC_SET(ts.tv_nsec),
466*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_BT_NSEC);
467*e462b271SHoratiu Vultur 
468*e462b271SHoratiu Vultur 	lan_wr(lower_32_bits(ts.tv_sec),
469*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_BT_SEC_LSB);
470*e462b271SHoratiu Vultur 
471*e462b271SHoratiu Vultur 	lan_wr(QSYS_TAS_BT_SEC_MSB_SEC_MSB_SET(upper_32_bits(ts.tv_sec)),
472*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_BT_SEC_MSB);
473*e462b271SHoratiu Vultur 
474*e462b271SHoratiu Vultur 	lan_wr(qopt->cycle_time, lan966x, QSYS_TAS_CT_CFG);
475*e462b271SHoratiu Vultur 
476*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX_SET(obs_list),
477*e462b271SHoratiu Vultur 		QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX,
478*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_STARTUP_CFG);
479*e462b271SHoratiu Vultur 
480*e462b271SHoratiu Vultur 	/* Start list processing */
481*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(LAN966X_TAPRIO_STATE_ADVANCING),
482*e462b271SHoratiu Vultur 		QSYS_TAS_LST_LIST_STATE,
483*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_LST);
484*e462b271SHoratiu Vultur 
485*e462b271SHoratiu Vultur 	return err;
486*e462b271SHoratiu Vultur }
487*e462b271SHoratiu Vultur 
lan966x_taprio_del(struct lan966x_port * port)488*e462b271SHoratiu Vultur int lan966x_taprio_del(struct lan966x_port *port)
489*e462b271SHoratiu Vultur {
490*e462b271SHoratiu Vultur 	return lan966x_taprio_shutdown(port);
491*e462b271SHoratiu Vultur }
492*e462b271SHoratiu Vultur 
lan966x_taprio_init(struct lan966x * lan966x)493*e462b271SHoratiu Vultur void lan966x_taprio_init(struct lan966x *lan966x)
494*e462b271SHoratiu Vultur {
495*e462b271SHoratiu Vultur 	int num_taprio_lists;
496*e462b271SHoratiu Vultur 	int p;
497*e462b271SHoratiu Vultur 
498*e462b271SHoratiu Vultur 	lan_wr(QSYS_TAS_STM_CFG_REVISIT_DLY_SET((256 * 1000) /
499*e462b271SHoratiu Vultur 						lan966x_ptp_get_period_ps()),
500*e462b271SHoratiu Vultur 	       lan966x, QSYS_TAS_STM_CFG);
501*e462b271SHoratiu Vultur 
502*e462b271SHoratiu Vultur 	num_taprio_lists = lan966x->num_phys_ports *
503*e462b271SHoratiu Vultur 			   LAN966X_TAPRIO_ENTRIES_PER_PORT;
504*e462b271SHoratiu Vultur 
505*e462b271SHoratiu Vultur 	/* For now we always use guard band on all queues */
506*e462b271SHoratiu Vultur 	lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_MAX_SET(num_taprio_lists) |
507*e462b271SHoratiu Vultur 		QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q_SET(1),
508*e462b271SHoratiu Vultur 		QSYS_TAS_CFG_CTRL_LIST_NUM_MAX |
509*e462b271SHoratiu Vultur 		QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q,
510*e462b271SHoratiu Vultur 		lan966x, QSYS_TAS_CFG_CTRL);
511*e462b271SHoratiu Vultur 
512*e462b271SHoratiu Vultur 	for (p = 0; p < lan966x->num_phys_ports; p++)
513*e462b271SHoratiu Vultur 		lan_rmw(QSYS_TAS_PROFILE_CFG_PORT_NUM_SET(p),
514*e462b271SHoratiu Vultur 			QSYS_TAS_PROFILE_CFG_PORT_NUM,
515*e462b271SHoratiu Vultur 			lan966x, QSYS_TAS_PROFILE_CFG(p));
516*e462b271SHoratiu Vultur }
517*e462b271SHoratiu Vultur 
lan966x_taprio_deinit(struct lan966x * lan966x)518*e462b271SHoratiu Vultur void lan966x_taprio_deinit(struct lan966x *lan966x)
519*e462b271SHoratiu Vultur {
520*e462b271SHoratiu Vultur 	int p;
521*e462b271SHoratiu Vultur 
522*e462b271SHoratiu Vultur 	for (p = 0; p < lan966x->num_phys_ports; ++p) {
523*e462b271SHoratiu Vultur 		if (!lan966x->ports[p])
524*e462b271SHoratiu Vultur 			continue;
525*e462b271SHoratiu Vultur 
526*e462b271SHoratiu Vultur 		lan966x_taprio_del(lan966x->ports[p]);
527*e462b271SHoratiu Vultur 	}
528*e462b271SHoratiu Vultur }
529