File Index
Files and directories
Sign in
FILE

txgbe_aml.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
  3
  4#include <linux/phylink.h>
  5#include <linux/iopoll.h>
  6#include <linux/pci.h>
  7#include <linux/phy.h>
  8
  9#include "../libwx/wx_type.h"
 10#include "../libwx/wx_lib.h"
 11#include "../libwx/wx_ptp.h"
 12#include "../libwx/wx_hw.h"
 13#include "../libwx/wx_sriov.h"
 14#include "txgbe_type.h"
 15#include "txgbe_aml.h"
 16#include "txgbe_hw.h"
 17
 18void txgbe_gpio_init_aml(struct wx *wx)
 19{
 20	u32 status, mod_rst;
 21
 22	if (wx->mac.type == wx_mac_aml40)
 23		mod_rst = TXGBE_GPIOBIT_4;
 24	else
 25		mod_rst = TXGBE_GPIOBIT_2;
 26
 27	wr32(wx, WX_GPIO_INTTYPE_LEVEL, mod_rst);
 28	wr32(wx, WX_GPIO_INTEN, mod_rst);
 29
 30	status = rd32(wx, WX_GPIO_INTSTATUS);
 31	for (int i = 0; i < 6; i++) {
 32		if (status & BIT(i))
 33			wr32(wx, WX_GPIO_EOI, BIT(i));
 34	}
 35}
 36
 37irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data)
 38{
 39	struct txgbe *txgbe = data;
 40	struct wx *wx = txgbe->wx;
 41	u32 status, mod_rst;
 42
 43	if (wx->mac.type == wx_mac_aml40)
 44		mod_rst = TXGBE_GPIOBIT_4;
 45	else
 46		mod_rst = TXGBE_GPIOBIT_2;
 47
 48	wr32(wx, WX_GPIO_INTMASK, 0xFF);
 49	status = rd32(wx, WX_GPIO_INTSTATUS);
 50	if (status & mod_rst) {
 51		set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
 52		wr32(wx, WX_GPIO_EOI, mod_rst);
 53		wx_service_event_schedule(wx);
 54	}
 55
 56	wr32(wx, WX_GPIO_INTMASK, 0);
 57	return IRQ_HANDLED;
 58}
 59
 60int txgbe_test_hostif(struct wx *wx)
 61{
 62	struct txgbe_hic_ephy_getlink buffer;
 63
 64	if (wx->mac.type == wx_mac_sp)
 65		return 0;
 66
 67	buffer.hdr.cmd = FW_PHY_GET_LINK_CMD;
 68	buffer.hdr.buf_len = sizeof(struct txgbe_hic_ephy_getlink) -
 69			     sizeof(struct wx_hic_hdr);
 70	buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
 71
 72	return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer),
 73					 WX_HI_COMMAND_TIMEOUT, false);
 74}
 75
 76int txgbe_read_eeprom_hostif(struct wx *wx,
 77			     struct txgbe_hic_i2c_read *buffer,
 78			     u32 length, u8 *data)
 79{
 80	u32 dword_len, offset, value, i;
 81	int err;
 82
 83	buffer->hdr.cmd = FW_READ_EEPROM_CMD;
 84	buffer->hdr.buf_len = sizeof(struct txgbe_hic_i2c_read) -
 85			      sizeof(struct wx_hic_hdr);
 86	buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
 87
 88	err = wx_host_interface_command(wx, (u32 *)buffer,
 89					sizeof(struct txgbe_hic_i2c_read),
 90					WX_HI_COMMAND_TIMEOUT, false);
 91	if (err != 0)
 92		return err;
 93
 94	/* buffer length offset to read return data */
 95	offset = sizeof(struct txgbe_hic_i2c_read) >> 2;
 96	dword_len = round_up(length, 4) >> 2;
 97
 98	for (i = 0; i < dword_len; i++) {
 99		value = rd32a(wx, WX_FW2SW_MBOX, i + offset);
100		le32_to_cpus(&value);
101
102		memcpy(data, &value, 4);
103		data += 4;
104	}
105
106	return 0;
107}
108
109static int txgbe_identify_module_hostif(struct wx *wx,
110					struct txgbe_hic_get_module_info *buffer)
111{
112	buffer->hdr.cmd = FW_GET_MODULE_INFO_CMD;
113	buffer->hdr.buf_len = sizeof(struct txgbe_hic_get_module_info) -
114			      sizeof(struct wx_hic_hdr);
115	buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
116
117	return wx_host_interface_command(wx, (u32 *)buffer,
118					 sizeof(struct txgbe_hic_get_module_info),
119					 WX_HI_COMMAND_TIMEOUT, true);
120}
121
122static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int duplex)
123{
124	struct txgbe_hic_ephy_setlink buffer;
125
126	buffer.hdr.cmd = FW_PHY_SET_LINK_CMD;
127	buffer.hdr.buf_len = sizeof(struct txgbe_hic_ephy_setlink) -
128			     sizeof(struct wx_hic_hdr);
129	buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
130
131	switch (speed) {
132	case SPEED_40000:
133		buffer.speed = TXGBE_LINK_SPEED_40GB_FULL;
134		break;
135	case SPEED_25000:
136		buffer.speed = TXGBE_LINK_SPEED_25GB_FULL;
137		break;
138	case SPEED_10000:
139		buffer.speed = TXGBE_LINK_SPEED_10GB_FULL;
140		break;
141	default:
142		buffer.speed = TXGBE_LINK_SPEED_UNKNOWN;
143		break;
144	}
145
146	buffer.fec_mode = TXGBE_PHY_FEC_AUTO;
147	buffer.autoneg = autoneg;
148	buffer.duplex = duplex;
149
150	return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer),
151					 WX_HI_COMMAND_TIMEOUT, false);
152}
153
154static void txgbe_get_link_capabilities(struct wx *wx, int *speed,
155					int *autoneg, int *duplex)
156{
157	struct txgbe *txgbe = wx->priv;
158
159	if (test_bit(PHY_INTERFACE_MODE_XLGMII, txgbe->link_interfaces))
160		*speed = SPEED_40000;
161	else if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->link_interfaces))
162		*speed = SPEED_25000;
163	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->link_interfaces))
164		*speed = SPEED_10000;
165	else
166		*speed = SPEED_UNKNOWN;
167
168	*autoneg = phylink_test(txgbe->advertising, Autoneg);
169	*duplex = *speed == SPEED_UNKNOWN ? DUPLEX_HALF : DUPLEX_FULL;
170}
171
172static void txgbe_get_mac_link(struct wx *wx, int *speed)
173{
174	u32 status;
175
176	status = rd32(wx, TXGBE_CFG_PORT_ST);
177	if (!(status & TXGBE_CFG_PORT_ST_LINK_UP))
178		*speed = SPEED_UNKNOWN;
179	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_40G)
180		*speed = SPEED_40000;
181	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_25G)
182		*speed = SPEED_25000;
183	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_10G)
184		*speed = SPEED_10000;
185	else
186		*speed = SPEED_UNKNOWN;
187}
188
189int txgbe_set_phy_link(struct wx *wx)
190{
191	int speed, autoneg, duplex, err;
192
193	txgbe_get_link_capabilities(wx, &speed, &autoneg, &duplex);
194
195	err = txgbe_set_phy_link_hostif(wx, speed, autoneg, duplex);
196	if (err) {
197		wx_err(wx, "Failed to setup link\n");
198		return err;
199	}
200
201	return 0;
202}
203
204static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
205{
206	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
207	DECLARE_PHY_INTERFACE_MASK(interfaces);
208	struct txgbe *txgbe = wx->priv;
209
210	if (id->cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) {
211		txgbe->link_port = PORT_DA;
212		phylink_set(modes, Autoneg);
213		if (id->com_25g_code == TXGBE_SFF_25GBASECR_91FEC ||
214		    id->com_25g_code == TXGBE_SFF_25GBASECR_74FEC ||
215		    id->com_25g_code == TXGBE_SFF_25GBASECR_NOFEC) {
216			phylink_set(modes, 25000baseCR_Full);
217			phylink_set(modes, 10000baseCR_Full);
218			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
219			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
220		} else {
221			phylink_set(modes, 10000baseCR_Full);
222			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
223		}
224	} else if (id->cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE) {
225		txgbe->link_port = PORT_DA;
226		phylink_set(modes, Autoneg);
227		phylink_set(modes, 25000baseCR_Full);
228		__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
229	} else {
230		if (id->com_25g_code == TXGBE_SFF_25GBASESR_CAPABLE ||
231		    id->com_25g_code == TXGBE_SFF_25GBASEER_CAPABLE ||
232		    id->com_25g_code == TXGBE_SFF_25GBASELR_CAPABLE) {
233			txgbe->link_port = PORT_FIBRE;
234			phylink_set(modes, 25000baseSR_Full);
235			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
236		}
237		if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) {
238			txgbe->link_port = PORT_FIBRE;
239			phylink_set(modes, 10000baseSR_Full);
240			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
241		}
242		if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) {
243			txgbe->link_port = PORT_FIBRE;
244			phylink_set(modes, 10000baseLR_Full);
245			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
246		}
247	}
248
249	if (phy_interface_empty(interfaces)) {
250		wx_err(wx, "unsupported SFP module\n");
251		return -EINVAL;
252	}
253
254	phylink_set(modes, Pause);
255	phylink_set(modes, Asym_Pause);
256	phylink_set(modes, FIBRE);
257
258	if (!linkmode_equal(txgbe->link_support, modes)) {
259		linkmode_copy(txgbe->link_support, modes);
260		phy_interface_and(txgbe->link_interfaces,
261				  wx->phylink_config.supported_interfaces,
262				  interfaces);
263		linkmode_copy(txgbe->advertising, modes);
264
265		set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
266	}
267
268	return 0;
269}
270
271static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
272{
273	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
274	DECLARE_PHY_INTERFACE_MASK(interfaces);
275	struct txgbe *txgbe = wx->priv;
276
277	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) {
278		txgbe->link_port = PORT_DA;
279		phylink_set(modes, Autoneg);
280		phylink_set(modes, 40000baseCR4_Full);
281		phylink_set(modes, 10000baseCR_Full);
282		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
283		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
284	}
285	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_SR4) {
286		txgbe->link_port = PORT_FIBRE;
287		phylink_set(modes, 40000baseSR4_Full);
288		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
289	}
290	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_LR4) {
291		txgbe->link_port = PORT_FIBRE;
292		phylink_set(modes, 40000baseLR4_Full);
293		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
294	}
295	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
296		txgbe->link_port = PORT_DA;
297		phylink_set(modes, Autoneg);
298		phylink_set(modes, 40000baseCR4_Full);
299		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
300	}
301	if (id->transceiver_type & TXGBE_SFF_ETHERNET_RSRVD) {
302		if (id->sff_opt1 & TXGBE_SFF_ETHERNET_100G_CR4) {
303			txgbe->link_port = PORT_DA;
304			phylink_set(modes, Autoneg);
305			phylink_set(modes, 40000baseCR4_Full);
306			phylink_set(modes, 25000baseCR_Full);
307			phylink_set(modes, 10000baseCR_Full);
308			__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
309			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
310			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
311		}
312	}
313
314	if (phy_interface_empty(interfaces)) {
315		wx_err(wx, "unsupported QSFP module\n");
316		return -EINVAL;
317	}
318
319	phylink_set(modes, Pause);
320	phylink_set(modes, Asym_Pause);
321	phylink_set(modes, FIBRE);
322
323	if (!linkmode_equal(txgbe->link_support, modes)) {
324		linkmode_copy(txgbe->link_support, modes);
325		phy_interface_and(txgbe->link_interfaces,
326				  wx->phylink_config.supported_interfaces,
327				  interfaces);
328		linkmode_copy(txgbe->advertising, modes);
329
330		set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
331	}
332
333	return 0;
334}
335
336int txgbe_identify_module(struct wx *wx)
337{
338	struct txgbe_hic_get_module_info buffer;
339	struct txgbe_sff_id *id;
340	int err = 0;
341	u32 mod_abs;
342	u32 gpio;
343
344	if (wx->mac.type == wx_mac_aml40)
345		mod_abs = TXGBE_GPIOBIT_4;
346	else
347		mod_abs = TXGBE_GPIOBIT_2;
348
349	gpio = rd32(wx, WX_GPIO_EXT);
350	if (gpio & mod_abs)
351		return -ENODEV;
352
353	err = txgbe_identify_module_hostif(wx, &buffer);
354	if (err) {
355		wx_err(wx, "Failed to identify module\n");
356		return err;
357	}
358
359	id = &buffer.id;
360	if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP &&
361	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP &&
362	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS &&
363	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP28) {
364		wx_err(wx, "Invalid module\n");
365		return -ENODEV;
366	}
367
368	if (id->transceiver_type == 0xFF)
369		return txgbe_sfp_to_linkmodes(wx, id);
370
371	return txgbe_qsfp_to_linkmodes(wx, id);
372}
373
374void txgbe_setup_link(struct wx *wx)
375{
376	struct txgbe *txgbe = wx->priv;
377
378	phy_interface_zero(txgbe->link_interfaces);
379	linkmode_zero(txgbe->link_support);
380
381	set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
382	wx_service_event_schedule(wx);
383}
384
385static void txgbe_get_link_state(struct phylink_config *config,
386				 struct phylink_link_state *state)
387{
388	struct wx *wx = phylink_to_wx(config);
389	int speed;
390
391	txgbe_get_mac_link(wx, &speed);
392	state->link = speed != SPEED_UNKNOWN;
393	state->speed = speed;
394	state->duplex = state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
395}
396
397static void txgbe_reconfig_mac(struct wx *wx)
398{
399	u32 wdg, fc;
400
401	wdg = rd32(wx, WX_MAC_WDG_TIMEOUT);
402	fc = rd32(wx, WX_MAC_RX_FLOW_CTRL);
403
404	wr32(wx, WX_MIS_RST, TXGBE_MIS_RST_MAC_RST(wx->bus.func));
405	/* wait for MAC reset complete */
406	usleep_range(1000, 1500);
407
408	wr32m(wx, TXGBE_MAC_MISC_CTL, TXGBE_MAC_MISC_CTL_LINK_STS_MOD,
409	      TXGBE_MAC_MISC_CTL_LINK_BOTH);
410	wx_reset_mac(wx);
411
412	wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
413	wr32(wx, WX_MAC_RX_FLOW_CTRL, fc);
414}
415
416static void txgbe_mac_link_up_aml(struct phylink_config *config,
417				  struct phy_device *phy,
418				  unsigned int mode,
419				  phy_interface_t interface,
420				  int speed, int duplex,
421				  bool tx_pause, bool rx_pause)
422{
423	struct wx *wx = phylink_to_wx(config);
424	u32 txcfg;
425
426	wx_fc_enable(wx, tx_pause, rx_pause);
427
428	txgbe_reconfig_mac(wx);
429	txgbe_enable_sec_tx_path(wx);
430
431	txcfg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
432	txcfg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
433
434	switch (speed) {
435	case SPEED_40000:
436		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
437		break;
438	case SPEED_25000:
439		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
440		break;
441	case SPEED_10000:
442		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_10G;
443		break;
444	default:
445		break;
446	}
447
448	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
449	wr32(wx, TXGBE_AML_MAC_TX_CFG, txcfg | TXGBE_AML_MAC_TX_CFG_TE);
450
451	wx->speed = speed;
452	wx->last_rx_ptp_check = jiffies;
453	if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
454		wx_ptp_reset_cyclecounter(wx);
455	/* ping all the active vfs to let them know we are going up */
456	wx_ping_all_vfs_with_link_status(wx, true);
457}
458
459static void txgbe_mac_link_down_aml(struct phylink_config *config,
460				    unsigned int mode,
461				    phy_interface_t interface)
462{
463	struct wx *wx = phylink_to_wx(config);
464
465	wr32m(wx, TXGBE_AML_MAC_TX_CFG, TXGBE_AML_MAC_TX_CFG_TE, 0);
466	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
467
468	wx->speed = SPEED_UNKNOWN;
469	if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
470		wx_ptp_reset_cyclecounter(wx);
471	/* ping all the active vfs to let them know we are going down */
472	wx_ping_all_vfs_with_link_status(wx, false);
473}
474
475static void txgbe_mac_config_aml(struct phylink_config *config, unsigned int mode,
476				 const struct phylink_link_state *state)
477{
478}
479
480static const struct phylink_mac_ops txgbe_mac_ops_aml = {
481	.mac_config = txgbe_mac_config_aml,
482	.mac_link_down = txgbe_mac_link_down_aml,
483	.mac_link_up = txgbe_mac_link_up_aml,
484};
485
486int txgbe_phylink_init_aml(struct txgbe *txgbe)
487{
488	struct phylink_link_state state;
489	struct phylink_config *config;
490	struct wx *wx = txgbe->wx;
491	phy_interface_t phy_mode;
492	struct phylink *phylink;
493	int err;
494
495	config = &wx->phylink_config;
496	config->dev = &wx->netdev->dev;
497	config->type = PHYLINK_NETDEV;
498	config->mac_capabilities = MAC_25000FD | MAC_10000FD |
499				   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
500	config->get_fixed_state = txgbe_get_link_state;
501
502	if (wx->mac.type == wx_mac_aml40) {
503		config->mac_capabilities |= MAC_40000FD;
504		phy_mode = PHY_INTERFACE_MODE_XLGMII;
505		__set_bit(PHY_INTERFACE_MODE_XLGMII, config->supported_interfaces);
506		state.speed = SPEED_40000;
507		state.duplex = DUPLEX_FULL;
508	} else {
509		phy_mode = PHY_INTERFACE_MODE_25GBASER;
510		state.speed = SPEED_25000;
511		state.duplex = DUPLEX_FULL;
512	}
513
514	__set_bit(PHY_INTERFACE_MODE_25GBASER, config->supported_interfaces);
515	__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
516
517	phylink = phylink_create(config, NULL, phy_mode, &txgbe_mac_ops_aml);
518	if (IS_ERR(phylink))
519		return PTR_ERR(phylink);
520
521	err = phylink_set_fixed_link(phylink, &state);
522	if (err) {
523		wx_err(wx, "Failed to set fixed link\n");
524		return err;
525	}
526
527	wx->phylink = phylink;
528
529	return 0;
530}
~/ Read-only file preview.