xref: /linux/drivers/net/ethernet/mscc/ocelot_mm.c (revision 6505b68056558357dc979d11921ed45cfd68ed69)
1*6505b680SVladimir Oltean // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2*6505b680SVladimir Oltean /*
3*6505b680SVladimir Oltean  * Hardware library for MAC Merge Layer and Frame Preemption on TSN-capable
4*6505b680SVladimir Oltean  * switches (VSC9959)
5*6505b680SVladimir Oltean  *
6*6505b680SVladimir Oltean  * Copyright 2022-2023 NXP
7*6505b680SVladimir Oltean  */
8*6505b680SVladimir Oltean #include <linux/ethtool.h>
9*6505b680SVladimir Oltean #include <soc/mscc/ocelot.h>
10*6505b680SVladimir Oltean #include <soc/mscc/ocelot_dev.h>
11*6505b680SVladimir Oltean #include <soc/mscc/ocelot_qsys.h>
12*6505b680SVladimir Oltean 
13*6505b680SVladimir Oltean #include "ocelot.h"
14*6505b680SVladimir Oltean 
15*6505b680SVladimir Oltean static const char *
16*6505b680SVladimir Oltean mm_verify_state_to_string(enum ethtool_mm_verify_status state)
17*6505b680SVladimir Oltean {
18*6505b680SVladimir Oltean 	switch (state) {
19*6505b680SVladimir Oltean 	case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
20*6505b680SVladimir Oltean 		return "INITIAL";
21*6505b680SVladimir Oltean 	case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
22*6505b680SVladimir Oltean 		return "VERIFYING";
23*6505b680SVladimir Oltean 	case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
24*6505b680SVladimir Oltean 		return "SUCCEEDED";
25*6505b680SVladimir Oltean 	case ETHTOOL_MM_VERIFY_STATUS_FAILED:
26*6505b680SVladimir Oltean 		return "FAILED";
27*6505b680SVladimir Oltean 	case ETHTOOL_MM_VERIFY_STATUS_DISABLED:
28*6505b680SVladimir Oltean 		return "DISABLED";
29*6505b680SVladimir Oltean 	default:
30*6505b680SVladimir Oltean 		return "UNKNOWN";
31*6505b680SVladimir Oltean 	}
32*6505b680SVladimir Oltean }
33*6505b680SVladimir Oltean 
34*6505b680SVladimir Oltean static enum ethtool_mm_verify_status ocelot_mm_verify_status(u32 val)
35*6505b680SVladimir Oltean {
36*6505b680SVladimir Oltean 	switch (DEV_MM_STAT_MM_STATUS_PRMPT_VERIFY_STATE_X(val)) {
37*6505b680SVladimir Oltean 	case 0:
38*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_INITIAL;
39*6505b680SVladimir Oltean 	case 1:
40*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
41*6505b680SVladimir Oltean 	case 2:
42*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
43*6505b680SVladimir Oltean 	case 3:
44*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_FAILED;
45*6505b680SVladimir Oltean 	case 4:
46*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_DISABLED;
47*6505b680SVladimir Oltean 	default:
48*6505b680SVladimir Oltean 		return ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
49*6505b680SVladimir Oltean 	}
50*6505b680SVladimir Oltean }
51*6505b680SVladimir Oltean 
52*6505b680SVladimir Oltean void ocelot_port_mm_irq(struct ocelot *ocelot, int port)
53*6505b680SVladimir Oltean {
54*6505b680SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
55*6505b680SVladimir Oltean 	struct ocelot_mm_state *mm = &ocelot->mm[port];
56*6505b680SVladimir Oltean 	enum ethtool_mm_verify_status verify_status;
57*6505b680SVladimir Oltean 	u32 val;
58*6505b680SVladimir Oltean 
59*6505b680SVladimir Oltean 	mutex_lock(&mm->lock);
60*6505b680SVladimir Oltean 
61*6505b680SVladimir Oltean 	val = ocelot_port_readl(ocelot_port, DEV_MM_STATUS);
62*6505b680SVladimir Oltean 
63*6505b680SVladimir Oltean 	verify_status = ocelot_mm_verify_status(val);
64*6505b680SVladimir Oltean 	if (mm->verify_status != verify_status) {
65*6505b680SVladimir Oltean 		dev_dbg(ocelot->dev,
66*6505b680SVladimir Oltean 			"Port %d MAC Merge verification state %s\n",
67*6505b680SVladimir Oltean 			port, mm_verify_state_to_string(verify_status));
68*6505b680SVladimir Oltean 		mm->verify_status = verify_status;
69*6505b680SVladimir Oltean 	}
70*6505b680SVladimir Oltean 
71*6505b680SVladimir Oltean 	if (val & DEV_MM_STAT_MM_STATUS_PRMPT_ACTIVE_STICKY) {
72*6505b680SVladimir Oltean 		mm->tx_active = !!(val & DEV_MM_STAT_MM_STATUS_PRMPT_ACTIVE_STATUS);
73*6505b680SVladimir Oltean 
74*6505b680SVladimir Oltean 		dev_dbg(ocelot->dev, "Port %d TX preemption %s\n",
75*6505b680SVladimir Oltean 			port, mm->tx_active ? "active" : "inactive");
76*6505b680SVladimir Oltean 	}
77*6505b680SVladimir Oltean 
78*6505b680SVladimir Oltean 	if (val & DEV_MM_STAT_MM_STATUS_UNEXP_RX_PFRM_STICKY) {
79*6505b680SVladimir Oltean 		dev_err(ocelot->dev,
80*6505b680SVladimir Oltean 			"Unexpected P-frame received on port %d while verification was unsuccessful or not yet verified\n",
81*6505b680SVladimir Oltean 			port);
82*6505b680SVladimir Oltean 	}
83*6505b680SVladimir Oltean 
84*6505b680SVladimir Oltean 	if (val & DEV_MM_STAT_MM_STATUS_UNEXP_TX_PFRM_STICKY) {
85*6505b680SVladimir Oltean 		dev_err(ocelot->dev,
86*6505b680SVladimir Oltean 			"Unexpected P-frame requested to be transmitted on port %d while verification was unsuccessful or not yet verified, or MM_TX_ENA=0\n",
87*6505b680SVladimir Oltean 			port);
88*6505b680SVladimir Oltean 	}
89*6505b680SVladimir Oltean 
90*6505b680SVladimir Oltean 	ocelot_port_writel(ocelot_port, val, DEV_MM_STATUS);
91*6505b680SVladimir Oltean 
92*6505b680SVladimir Oltean 	mutex_unlock(&mm->lock);
93*6505b680SVladimir Oltean }
94*6505b680SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_mm_irq);
95*6505b680SVladimir Oltean 
96*6505b680SVladimir Oltean int ocelot_port_set_mm(struct ocelot *ocelot, int port,
97*6505b680SVladimir Oltean 		       struct ethtool_mm_cfg *cfg,
98*6505b680SVladimir Oltean 		       struct netlink_ext_ack *extack)
99*6505b680SVladimir Oltean {
100*6505b680SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
101*6505b680SVladimir Oltean 	u32 mm_enable = 0, verify_disable = 0, add_frag_size;
102*6505b680SVladimir Oltean 	struct ocelot_mm_state *mm;
103*6505b680SVladimir Oltean 	int err;
104*6505b680SVladimir Oltean 
105*6505b680SVladimir Oltean 	if (!ocelot->mm_supported)
106*6505b680SVladimir Oltean 		return -EOPNOTSUPP;
107*6505b680SVladimir Oltean 
108*6505b680SVladimir Oltean 	mm = &ocelot->mm[port];
109*6505b680SVladimir Oltean 
110*6505b680SVladimir Oltean 	err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size,
111*6505b680SVladimir Oltean 					      &add_frag_size, extack);
112*6505b680SVladimir Oltean 	if (err)
113*6505b680SVladimir Oltean 		return err;
114*6505b680SVladimir Oltean 
115*6505b680SVladimir Oltean 	if (cfg->pmac_enabled)
116*6505b680SVladimir Oltean 		mm_enable |= DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA;
117*6505b680SVladimir Oltean 
118*6505b680SVladimir Oltean 	if (cfg->tx_enabled)
119*6505b680SVladimir Oltean 		mm_enable |= DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA;
120*6505b680SVladimir Oltean 
121*6505b680SVladimir Oltean 	if (!cfg->verify_enabled)
122*6505b680SVladimir Oltean 		verify_disable = DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS;
123*6505b680SVladimir Oltean 
124*6505b680SVladimir Oltean 	mutex_lock(&mm->lock);
125*6505b680SVladimir Oltean 
126*6505b680SVladimir Oltean 	ocelot_port_rmwl(ocelot_port, mm_enable,
127*6505b680SVladimir Oltean 			 DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA |
128*6505b680SVladimir Oltean 			 DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA,
129*6505b680SVladimir Oltean 			 DEV_MM_ENABLE_CONFIG);
130*6505b680SVladimir Oltean 
131*6505b680SVladimir Oltean 	ocelot_port_rmwl(ocelot_port, verify_disable |
132*6505b680SVladimir Oltean 			 DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(cfg->verify_time),
133*6505b680SVladimir Oltean 			 DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS |
134*6505b680SVladimir Oltean 			 DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M,
135*6505b680SVladimir Oltean 			 DEV_MM_VERIF_CONFIG);
136*6505b680SVladimir Oltean 
137*6505b680SVladimir Oltean 	ocelot_rmw_rix(ocelot,
138*6505b680SVladimir Oltean 		       QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(add_frag_size),
139*6505b680SVladimir Oltean 		       QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M,
140*6505b680SVladimir Oltean 		       QSYS_PREEMPTION_CFG,
141*6505b680SVladimir Oltean 		       port);
142*6505b680SVladimir Oltean 
143*6505b680SVladimir Oltean 	mutex_unlock(&mm->lock);
144*6505b680SVladimir Oltean 
145*6505b680SVladimir Oltean 	return 0;
146*6505b680SVladimir Oltean }
147*6505b680SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_set_mm);
148*6505b680SVladimir Oltean 
149*6505b680SVladimir Oltean int ocelot_port_get_mm(struct ocelot *ocelot, int port,
150*6505b680SVladimir Oltean 		       struct ethtool_mm_state *state)
151*6505b680SVladimir Oltean {
152*6505b680SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
153*6505b680SVladimir Oltean 	struct ocelot_mm_state *mm;
154*6505b680SVladimir Oltean 	u32 val, add_frag_size;
155*6505b680SVladimir Oltean 
156*6505b680SVladimir Oltean 	if (!ocelot->mm_supported)
157*6505b680SVladimir Oltean 		return -EOPNOTSUPP;
158*6505b680SVladimir Oltean 
159*6505b680SVladimir Oltean 	mm = &ocelot->mm[port];
160*6505b680SVladimir Oltean 
161*6505b680SVladimir Oltean 	mutex_lock(&mm->lock);
162*6505b680SVladimir Oltean 
163*6505b680SVladimir Oltean 	val = ocelot_port_readl(ocelot_port, DEV_MM_ENABLE_CONFIG);
164*6505b680SVladimir Oltean 	state->pmac_enabled = !!(val & DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA);
165*6505b680SVladimir Oltean 	state->tx_enabled = !!(val & DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA);
166*6505b680SVladimir Oltean 
167*6505b680SVladimir Oltean 	val = ocelot_port_readl(ocelot_port, DEV_MM_VERIF_CONFIG);
168*6505b680SVladimir Oltean 	state->verify_time = DEV_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(val);
169*6505b680SVladimir Oltean 	state->max_verify_time = 128;
170*6505b680SVladimir Oltean 
171*6505b680SVladimir Oltean 	val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port);
172*6505b680SVladimir Oltean 	add_frag_size = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
173*6505b680SVladimir Oltean 	state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
174*6505b680SVladimir Oltean 	state->rx_min_frag_size = ETH_ZLEN;
175*6505b680SVladimir Oltean 
176*6505b680SVladimir Oltean 	state->verify_status = mm->verify_status;
177*6505b680SVladimir Oltean 	state->tx_active = mm->tx_active;
178*6505b680SVladimir Oltean 
179*6505b680SVladimir Oltean 	mutex_unlock(&mm->lock);
180*6505b680SVladimir Oltean 
181*6505b680SVladimir Oltean 	return 0;
182*6505b680SVladimir Oltean }
183*6505b680SVladimir Oltean EXPORT_SYMBOL_GPL(ocelot_port_get_mm);
184*6505b680SVladimir Oltean 
185*6505b680SVladimir Oltean int ocelot_mm_init(struct ocelot *ocelot)
186*6505b680SVladimir Oltean {
187*6505b680SVladimir Oltean 	struct ocelot_port *ocelot_port;
188*6505b680SVladimir Oltean 	struct ocelot_mm_state *mm;
189*6505b680SVladimir Oltean 	int port;
190*6505b680SVladimir Oltean 
191*6505b680SVladimir Oltean 	if (!ocelot->mm_supported)
192*6505b680SVladimir Oltean 		return 0;
193*6505b680SVladimir Oltean 
194*6505b680SVladimir Oltean 	ocelot->mm = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
195*6505b680SVladimir Oltean 				  sizeof(*ocelot->mm), GFP_KERNEL);
196*6505b680SVladimir Oltean 	if (!ocelot->mm)
197*6505b680SVladimir Oltean 		return -ENOMEM;
198*6505b680SVladimir Oltean 
199*6505b680SVladimir Oltean 	for (port = 0; port < ocelot->num_phys_ports; port++) {
200*6505b680SVladimir Oltean 		u32 val;
201*6505b680SVladimir Oltean 
202*6505b680SVladimir Oltean 		mm = &ocelot->mm[port];
203*6505b680SVladimir Oltean 		mutex_init(&mm->lock);
204*6505b680SVladimir Oltean 		ocelot_port = ocelot->ports[port];
205*6505b680SVladimir Oltean 
206*6505b680SVladimir Oltean 		/* Update initial status variable for the
207*6505b680SVladimir Oltean 		 * verification state machine
208*6505b680SVladimir Oltean 		 */
209*6505b680SVladimir Oltean 		val = ocelot_port_readl(ocelot_port, DEV_MM_STATUS);
210*6505b680SVladimir Oltean 		mm->verify_status = ocelot_mm_verify_status(val);
211*6505b680SVladimir Oltean 	}
212*6505b680SVladimir Oltean 
213*6505b680SVladimir Oltean 	return 0;
214*6505b680SVladimir Oltean }
215