File Index
Files and directories
Sign in
FILE

hbg_diagnose.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/hisilicon/hibmcge/hbg_diagnose.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2// Copyright (c) 2025 Hisilicon Limited.
  3
  4#include <linux/iopoll.h>
  5#include <linux/phy.h>
  6#include "hbg_common.h"
  7#include "hbg_ethtool.h"
  8#include "hbg_hw.h"
  9#include "hbg_diagnose.h"
 10
 11#define HBG_MSG_DATA_MAX_NUM	64
 12
 13struct hbg_diagnose_message {
 14	u32 opcode;
 15	u32 status;
 16	u32 data_num;
 17	struct hbg_priv *priv;
 18
 19	u32 data[HBG_MSG_DATA_MAX_NUM];
 20};
 21
 22#define HBG_HW_PUSH_WAIT_TIMEOUT_US	(2 * 1000 * 1000)
 23#define HBG_HW_PUSH_WAIT_INTERVAL_US	(1 * 1000)
 24
 25enum hbg_push_cmd {
 26	HBG_PUSH_CMD_IRQ = 0,
 27	HBG_PUSH_CMD_STATS,
 28	HBG_PUSH_CMD_LINK,
 29};
 30
 31struct hbg_push_stats_info {
 32	/* id is used to match the name of the current stats item.
 33	 * and is used for pretty print on BMC
 34	 */
 35	u32 id;
 36	u64 offset;
 37};
 38
 39struct hbg_push_irq_info {
 40	/* id is used to match the name of the current irq.
 41	 * and is used for pretty print on BMC
 42	 */
 43	u32 id;
 44	u32 mask;
 45};
 46
 47#define HBG_PUSH_IRQ_I(name, id) {id, HBG_INT_MSK_##name##_B}
 48static const struct hbg_push_irq_info hbg_push_irq_list[] = {
 49	HBG_PUSH_IRQ_I(RX, 0),
 50	HBG_PUSH_IRQ_I(TX, 1),
 51	HBG_PUSH_IRQ_I(TX_PKT_CPL, 2),
 52	HBG_PUSH_IRQ_I(MAC_MII_FIFO_ERR, 3),
 53	HBG_PUSH_IRQ_I(MAC_PCS_RX_FIFO_ERR, 4),
 54	HBG_PUSH_IRQ_I(MAC_PCS_TX_FIFO_ERR, 5),
 55	HBG_PUSH_IRQ_I(MAC_APP_RX_FIFO_ERR, 6),
 56	HBG_PUSH_IRQ_I(MAC_APP_TX_FIFO_ERR, 7),
 57	HBG_PUSH_IRQ_I(SRAM_PARITY_ERR, 8),
 58	HBG_PUSH_IRQ_I(TX_AHB_ERR, 9),
 59	HBG_PUSH_IRQ_I(RX_BUF_AVL, 10),
 60	HBG_PUSH_IRQ_I(REL_BUF_ERR, 11),
 61	HBG_PUSH_IRQ_I(TXCFG_AVL, 12),
 62	HBG_PUSH_IRQ_I(TX_DROP, 13),
 63	HBG_PUSH_IRQ_I(RX_DROP, 14),
 64	HBG_PUSH_IRQ_I(RX_AHB_ERR, 15),
 65	HBG_PUSH_IRQ_I(MAC_FIFO_ERR, 16),
 66	HBG_PUSH_IRQ_I(RBREQ_ERR, 17),
 67	HBG_PUSH_IRQ_I(WE_ERR, 18),
 68};
 69
 70#define HBG_PUSH_STATS_I(name, id) {id, HBG_STATS_FIELD_OFF(name)}
 71static const struct hbg_push_stats_info hbg_push_stats_list[] = {
 72	HBG_PUSH_STATS_I(rx_desc_drop, 0),
 73	HBG_PUSH_STATS_I(rx_desc_l2_err_cnt, 1),
 74	HBG_PUSH_STATS_I(rx_desc_pkt_len_err_cnt, 2),
 75	HBG_PUSH_STATS_I(rx_desc_l3_wrong_head_cnt, 3),
 76	HBG_PUSH_STATS_I(rx_desc_l3_csum_err_cnt, 4),
 77	HBG_PUSH_STATS_I(rx_desc_l3_len_err_cnt, 5),
 78	HBG_PUSH_STATS_I(rx_desc_l3_zero_ttl_cnt, 6),
 79	HBG_PUSH_STATS_I(rx_desc_l3_other_cnt, 7),
 80	HBG_PUSH_STATS_I(rx_desc_l4_err_cnt, 8),
 81	HBG_PUSH_STATS_I(rx_desc_l4_wrong_head_cnt, 9),
 82	HBG_PUSH_STATS_I(rx_desc_l4_len_err_cnt, 10),
 83	HBG_PUSH_STATS_I(rx_desc_l4_csum_err_cnt, 11),
 84	HBG_PUSH_STATS_I(rx_desc_l4_zero_port_num_cnt, 12),
 85	HBG_PUSH_STATS_I(rx_desc_l4_other_cnt, 13),
 86	HBG_PUSH_STATS_I(rx_desc_frag_cnt, 14),
 87	HBG_PUSH_STATS_I(rx_desc_ip_ver_err_cnt, 15),
 88	HBG_PUSH_STATS_I(rx_desc_ipv4_pkt_cnt, 16),
 89	HBG_PUSH_STATS_I(rx_desc_ipv6_pkt_cnt, 17),
 90	HBG_PUSH_STATS_I(rx_desc_no_ip_pkt_cnt, 18),
 91	HBG_PUSH_STATS_I(rx_desc_ip_pkt_cnt, 19),
 92	HBG_PUSH_STATS_I(rx_desc_tcp_pkt_cnt, 20),
 93	HBG_PUSH_STATS_I(rx_desc_udp_pkt_cnt, 21),
 94	HBG_PUSH_STATS_I(rx_desc_vlan_pkt_cnt, 22),
 95	HBG_PUSH_STATS_I(rx_desc_icmp_pkt_cnt, 23),
 96	HBG_PUSH_STATS_I(rx_desc_arp_pkt_cnt, 24),
 97	HBG_PUSH_STATS_I(rx_desc_rarp_pkt_cnt, 25),
 98	HBG_PUSH_STATS_I(rx_desc_multicast_pkt_cnt, 26),
 99	HBG_PUSH_STATS_I(rx_desc_broadcast_pkt_cnt, 27),
100	HBG_PUSH_STATS_I(rx_desc_ipsec_pkt_cnt, 28),
101	HBG_PUSH_STATS_I(rx_desc_ip_opt_pkt_cnt, 29),
102	HBG_PUSH_STATS_I(rx_desc_key_not_match_cnt, 30),
103	HBG_PUSH_STATS_I(rx_octets_total_ok_cnt, 31),
104	HBG_PUSH_STATS_I(rx_uc_pkt_cnt, 32),
105	HBG_PUSH_STATS_I(rx_mc_pkt_cnt, 33),
106	HBG_PUSH_STATS_I(rx_bc_pkt_cnt, 34),
107	HBG_PUSH_STATS_I(rx_vlan_pkt_cnt, 35),
108	HBG_PUSH_STATS_I(rx_octets_bad_cnt, 36),
109	HBG_PUSH_STATS_I(rx_octets_total_filt_cnt, 37),
110	HBG_PUSH_STATS_I(rx_filt_pkt_cnt, 38),
111	HBG_PUSH_STATS_I(rx_trans_pkt_cnt, 39),
112	HBG_PUSH_STATS_I(rx_framesize_64, 40),
113	HBG_PUSH_STATS_I(rx_framesize_65_127, 41),
114	HBG_PUSH_STATS_I(rx_framesize_128_255, 42),
115	HBG_PUSH_STATS_I(rx_framesize_256_511, 43),
116	HBG_PUSH_STATS_I(rx_framesize_512_1023, 44),
117	HBG_PUSH_STATS_I(rx_framesize_1024_1518, 45),
118	HBG_PUSH_STATS_I(rx_framesize_bt_1518, 46),
119	HBG_PUSH_STATS_I(rx_fcs_error_cnt, 47),
120	HBG_PUSH_STATS_I(rx_data_error_cnt, 48),
121	HBG_PUSH_STATS_I(rx_align_error_cnt, 49),
122	HBG_PUSH_STATS_I(rx_frame_long_err_cnt, 50),
123	HBG_PUSH_STATS_I(rx_jabber_err_cnt, 51),
124	HBG_PUSH_STATS_I(rx_pause_macctl_frame_cnt, 52),
125	HBG_PUSH_STATS_I(rx_unknown_macctl_frame_cnt, 53),
126	HBG_PUSH_STATS_I(rx_frame_very_long_err_cnt, 54),
127	HBG_PUSH_STATS_I(rx_frame_runt_err_cnt, 55),
128	HBG_PUSH_STATS_I(rx_frame_short_err_cnt, 56),
129	HBG_PUSH_STATS_I(rx_overflow_cnt, 57),
130	HBG_PUSH_STATS_I(rx_bufrq_err_cnt, 58),
131	HBG_PUSH_STATS_I(rx_we_err_cnt, 59),
132	HBG_PUSH_STATS_I(rx_overrun_cnt, 60),
133	HBG_PUSH_STATS_I(rx_lengthfield_err_cnt, 61),
134	HBG_PUSH_STATS_I(rx_fail_comma_cnt, 62),
135	HBG_PUSH_STATS_I(rx_dma_err_cnt, 63),
136	HBG_PUSH_STATS_I(rx_fifo_less_empty_thrsld_cnt, 64),
137	HBG_PUSH_STATS_I(tx_octets_total_ok_cnt, 65),
138	HBG_PUSH_STATS_I(tx_uc_pkt_cnt, 66),
139	HBG_PUSH_STATS_I(tx_mc_pkt_cnt, 67),
140	HBG_PUSH_STATS_I(tx_bc_pkt_cnt, 68),
141	HBG_PUSH_STATS_I(tx_vlan_pkt_cnt, 69),
142	HBG_PUSH_STATS_I(tx_octets_bad_cnt, 70),
143	HBG_PUSH_STATS_I(tx_trans_pkt_cnt, 71),
144	HBG_PUSH_STATS_I(tx_pause_frame_cnt, 72),
145	HBG_PUSH_STATS_I(tx_framesize_64, 73),
146	HBG_PUSH_STATS_I(tx_framesize_65_127, 74),
147	HBG_PUSH_STATS_I(tx_framesize_128_255, 75),
148	HBG_PUSH_STATS_I(tx_framesize_256_511, 76),
149	HBG_PUSH_STATS_I(tx_framesize_512_1023, 77),
150	HBG_PUSH_STATS_I(tx_framesize_1024_1518, 78),
151	HBG_PUSH_STATS_I(tx_framesize_bt_1518, 79),
152	HBG_PUSH_STATS_I(tx_underrun_err_cnt, 80),
153	HBG_PUSH_STATS_I(tx_add_cs_fail_cnt, 81),
154	HBG_PUSH_STATS_I(tx_bufrl_err_cnt, 82),
155	HBG_PUSH_STATS_I(tx_crc_err_cnt, 83),
156	HBG_PUSH_STATS_I(tx_drop_cnt, 84),
157	HBG_PUSH_STATS_I(tx_excessive_length_drop_cnt, 85),
158	HBG_PUSH_STATS_I(tx_dma_err_cnt, 86),
159	HBG_PUSH_STATS_I(reset_fail_cnt, 87),
160};
161
162static int hbg_push_msg_send(struct hbg_priv *priv,
163			     struct hbg_diagnose_message *msg)
164{
165	u32 header = 0;
166	u32 i;
167
168	if (msg->data_num == 0)
169		return 0;
170
171	for (i = 0; i < msg->data_num && i < HBG_MSG_DATA_MAX_NUM; i++)
172		hbg_reg_write(priv,
173			      HBG_REG_MSG_DATA_BASE_ADDR + i * sizeof(u32),
174			      msg->data[i]);
175
176	hbg_field_modify(header, HBG_REG_MSG_HEADER_OPCODE_M, msg->opcode);
177	hbg_field_modify(header, HBG_REG_MSG_HEADER_DATA_NUM_M,  msg->data_num);
178	hbg_field_modify(header, HBG_REG_MSG_HEADER_RESP_CODE_M, ETIMEDOUT);
179
180	/* start status */
181	hbg_field_modify(header, HBG_REG_MSG_HEADER_STATUS_M, 1);
182
183	/* write header msg to start push */
184	hbg_reg_write(priv, HBG_REG_MSG_HEADER_ADDR, header);
185
186	/* wait done */
187	readl_poll_timeout(priv->io_base + HBG_REG_MSG_HEADER_ADDR, header,
188			   !FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header),
189			   HBG_HW_PUSH_WAIT_INTERVAL_US,
190			   HBG_HW_PUSH_WAIT_TIMEOUT_US);
191
192	msg->status = FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header);
193	return -(int)FIELD_GET(HBG_REG_MSG_HEADER_RESP_CODE_M, header);
194}
195
196static int hbg_push_data(struct hbg_priv *priv,
197			 u32 opcode, u32 *data, u32 data_num)
198{
199	struct hbg_diagnose_message msg = {0};
200	u32 data_left_num;
201	u32 i, j;
202	int ret;
203
204	msg.priv = priv;
205	msg.opcode = opcode;
206	for (i = 0; i < data_num / HBG_MSG_DATA_MAX_NUM + 1; i++) {
207		if (i * HBG_MSG_DATA_MAX_NUM >= data_num)
208			break;
209
210		data_left_num = data_num - i * HBG_MSG_DATA_MAX_NUM;
211		for (j = 0; j < data_left_num && j < HBG_MSG_DATA_MAX_NUM; j++)
212			msg.data[j] = data[i * HBG_MSG_DATA_MAX_NUM + j];
213
214		msg.data_num = j;
215		ret = hbg_push_msg_send(priv, &msg);
216		if (ret)
217			return ret;
218	}
219
220	return 0;
221}
222
223static int hbg_push_data_u64(struct hbg_priv *priv, u32 opcode,
224			     u64 *data, u32 data_num)
225{
226	/* The length of u64 is twice that of u32,
227	 * the data_num must be multiplied by 2.
228	 */
229	return hbg_push_data(priv, opcode, (u32 *)data, data_num * 2);
230}
231
232static u64 hbg_get_irq_stats(struct hbg_vector *vectors, u32 mask)
233{
234	u32 i = 0;
235
236	for (i = 0; i < vectors->info_array_len; i++)
237		if (vectors->info_array[i].mask == mask)
238			return vectors->stats_array[i];
239
240	return 0;
241}
242
243static int hbg_push_irq_cnt(struct hbg_priv *priv)
244{
245	/* An id needs to be added for each data.
246	 * Therefore, the data_num must be multiplied by 2.
247	 */
248	u32 data_num = ARRAY_SIZE(hbg_push_irq_list) * 2;
249	struct hbg_vector *vectors = &priv->vectors;
250	const struct hbg_push_irq_info *info;
251	u32 i, j = 0;
252	u64 *data;
253	int ret;
254
255	data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
256	if (!data)
257		return -ENOMEM;
258
259	/* An id needs to be added for each data.
260	 * So i + 2 for each loop.
261	 */
262	for (i = 0; i < data_num; i += 2) {
263		info = &hbg_push_irq_list[j++];
264		data[i] = info->id;
265		data[i + 1] = hbg_get_irq_stats(vectors, info->mask);
266	}
267
268	ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_IRQ, data, data_num);
269	kfree(data);
270	return ret;
271}
272
273static int hbg_push_link_status(struct hbg_priv *priv)
274{
275	u32 link_status[2];
276
277	/* phy link status */
278	link_status[0] = priv->mac.phydev->link;
279	/* mac link status */
280	link_status[1] = hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
281					    HBG_REG_AN_NEG_STATE_NP_LINK_OK_B);
282
283	return hbg_push_data(priv, HBG_PUSH_CMD_LINK,
284			     link_status, ARRAY_SIZE(link_status));
285}
286
287static int hbg_push_stats(struct hbg_priv *priv)
288{
289	/* An id needs to be added for each data.
290	 * Therefore, the data_num must be multiplied by 2.
291	 */
292	u64 data_num = ARRAY_SIZE(hbg_push_stats_list) * 2;
293	struct hbg_stats *stats = &priv->stats;
294	const struct hbg_push_stats_info *info;
295	u32 i, j = 0;
296	u64 *data;
297	int ret;
298
299	data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
300	if (!data)
301		return -ENOMEM;
302
303	/* An id needs to be added for each data.
304	 * So i + 2 for each loop.
305	 */
306	for (i = 0; i < data_num; i += 2) {
307		info = &hbg_push_stats_list[j++];
308		data[i] = info->id;
309		data[i + 1] = HBG_STATS_R(stats, info->offset);
310	}
311
312	ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_STATS, data, data_num);
313	kfree(data);
314	return ret;
315}
316
317void hbg_diagnose_message_push(struct hbg_priv *priv)
318{
319	int ret;
320
321	if (test_bit(HBG_NIC_STATE_RESETTING, &priv->state))
322		return;
323
324	/* only 1 is the right value */
325	if (hbg_reg_read(priv, HBG_REG_PUSH_REQ_ADDR) != 1)
326		return;
327
328	ret = hbg_push_irq_cnt(priv);
329	if (ret) {
330		dev_err(&priv->pdev->dev,
331			"failed to push irq cnt, ret = %d\n", ret);
332		goto push_done;
333	}
334
335	ret = hbg_push_link_status(priv);
336	if (ret) {
337		dev_err(&priv->pdev->dev,
338			"failed to push link status, ret = %d\n", ret);
339		goto push_done;
340	}
341
342	ret = hbg_push_stats(priv);
343	if (ret)
344		dev_err(&priv->pdev->dev,
345			"failed to push stats, ret = %d\n", ret);
346
347push_done:
348	hbg_reg_write(priv, HBG_REG_PUSH_REQ_ADDR, 0);
349}
~/ Read-only file preview.