17a5d60dcSJijie Shao // SPDX-License-Identifier: GPL-2.0+
27a5d60dcSJijie Shao // Copyright (c) 2025 Hisilicon Limited.
37a5d60dcSJijie Shao
47a5d60dcSJijie Shao #include <linux/iopoll.h>
57a5d60dcSJijie Shao #include <linux/phy.h>
67a5d60dcSJijie Shao #include "hbg_common.h"
77a5d60dcSJijie Shao #include "hbg_ethtool.h"
87a5d60dcSJijie Shao #include "hbg_hw.h"
97a5d60dcSJijie Shao #include "hbg_diagnose.h"
107a5d60dcSJijie Shao
117a5d60dcSJijie Shao #define HBG_MSG_DATA_MAX_NUM 64
127a5d60dcSJijie Shao
137a5d60dcSJijie Shao struct hbg_diagnose_message {
147a5d60dcSJijie Shao u32 opcode;
157a5d60dcSJijie Shao u32 status;
167a5d60dcSJijie Shao u32 data_num;
177a5d60dcSJijie Shao struct hbg_priv *priv;
187a5d60dcSJijie Shao
197a5d60dcSJijie Shao u32 data[HBG_MSG_DATA_MAX_NUM];
207a5d60dcSJijie Shao };
217a5d60dcSJijie Shao
227a5d60dcSJijie Shao #define HBG_HW_PUSH_WAIT_TIMEOUT_US (2 * 1000 * 1000)
237a5d60dcSJijie Shao #define HBG_HW_PUSH_WAIT_INTERVAL_US (1 * 1000)
247a5d60dcSJijie Shao
257a5d60dcSJijie Shao enum hbg_push_cmd {
267a5d60dcSJijie Shao HBG_PUSH_CMD_IRQ = 0,
277a5d60dcSJijie Shao HBG_PUSH_CMD_STATS,
287a5d60dcSJijie Shao HBG_PUSH_CMD_LINK,
297a5d60dcSJijie Shao };
307a5d60dcSJijie Shao
317a5d60dcSJijie Shao struct hbg_push_stats_info {
327a5d60dcSJijie Shao /* id is used to match the name of the current stats item.
337a5d60dcSJijie Shao * and is used for pretty print on BMC
347a5d60dcSJijie Shao */
357a5d60dcSJijie Shao u32 id;
367a5d60dcSJijie Shao u64 offset;
377a5d60dcSJijie Shao };
387a5d60dcSJijie Shao
397a5d60dcSJijie Shao struct hbg_push_irq_info {
407a5d60dcSJijie Shao /* id is used to match the name of the current irq.
417a5d60dcSJijie Shao * and is used for pretty print on BMC
427a5d60dcSJijie Shao */
437a5d60dcSJijie Shao u32 id;
447a5d60dcSJijie Shao u32 mask;
457a5d60dcSJijie Shao };
467a5d60dcSJijie Shao
477a5d60dcSJijie Shao #define HBG_PUSH_IRQ_I(name, id) {id, HBG_INT_MSK_##name##_B}
487a5d60dcSJijie Shao static const struct hbg_push_irq_info hbg_push_irq_list[] = {
497a5d60dcSJijie Shao HBG_PUSH_IRQ_I(RX, 0),
507a5d60dcSJijie Shao HBG_PUSH_IRQ_I(TX, 1),
517a5d60dcSJijie Shao HBG_PUSH_IRQ_I(TX_PKT_CPL, 2),
527a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_MII_FIFO_ERR, 3),
537a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_PCS_RX_FIFO_ERR, 4),
547a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_PCS_TX_FIFO_ERR, 5),
557a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_APP_RX_FIFO_ERR, 6),
567a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_APP_TX_FIFO_ERR, 7),
577a5d60dcSJijie Shao HBG_PUSH_IRQ_I(SRAM_PARITY_ERR, 8),
587a5d60dcSJijie Shao HBG_PUSH_IRQ_I(TX_AHB_ERR, 9),
597a5d60dcSJijie Shao HBG_PUSH_IRQ_I(RX_BUF_AVL, 10),
607a5d60dcSJijie Shao HBG_PUSH_IRQ_I(REL_BUF_ERR, 11),
617a5d60dcSJijie Shao HBG_PUSH_IRQ_I(TXCFG_AVL, 12),
627a5d60dcSJijie Shao HBG_PUSH_IRQ_I(TX_DROP, 13),
637a5d60dcSJijie Shao HBG_PUSH_IRQ_I(RX_DROP, 14),
647a5d60dcSJijie Shao HBG_PUSH_IRQ_I(RX_AHB_ERR, 15),
657a5d60dcSJijie Shao HBG_PUSH_IRQ_I(MAC_FIFO_ERR, 16),
667a5d60dcSJijie Shao HBG_PUSH_IRQ_I(RBREQ_ERR, 17),
677a5d60dcSJijie Shao HBG_PUSH_IRQ_I(WE_ERR, 18),
687a5d60dcSJijie Shao };
697a5d60dcSJijie Shao
707a5d60dcSJijie Shao #define HBG_PUSH_STATS_I(name, id) {id, HBG_STATS_FIELD_OFF(name)}
717a5d60dcSJijie Shao static const struct hbg_push_stats_info hbg_push_stats_list[] = {
727a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_drop, 0),
737a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l2_err_cnt, 1),
747a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_pkt_len_err_cnt, 2),
757a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l3_wrong_head_cnt, 3),
767a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l3_csum_err_cnt, 4),
777a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l3_len_err_cnt, 5),
787a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l3_zero_ttl_cnt, 6),
797a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l3_other_cnt, 7),
807a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_err_cnt, 8),
817a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_wrong_head_cnt, 9),
827a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_len_err_cnt, 10),
837a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_csum_err_cnt, 11),
847a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_zero_port_num_cnt, 12),
857a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_l4_other_cnt, 13),
867a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_frag_cnt, 14),
877a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ip_ver_err_cnt, 15),
887a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ipv4_pkt_cnt, 16),
897a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ipv6_pkt_cnt, 17),
907a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_no_ip_pkt_cnt, 18),
917a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ip_pkt_cnt, 19),
927a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_tcp_pkt_cnt, 20),
937a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_udp_pkt_cnt, 21),
947a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_vlan_pkt_cnt, 22),
957a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_icmp_pkt_cnt, 23),
967a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_arp_pkt_cnt, 24),
977a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_rarp_pkt_cnt, 25),
987a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_multicast_pkt_cnt, 26),
997a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_broadcast_pkt_cnt, 27),
1007a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ipsec_pkt_cnt, 28),
1017a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_ip_opt_pkt_cnt, 29),
1027a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_desc_key_not_match_cnt, 30),
1037a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_octets_total_ok_cnt, 31),
1047a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_uc_pkt_cnt, 32),
1057a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_mc_pkt_cnt, 33),
1067a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_bc_pkt_cnt, 34),
1077a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_vlan_pkt_cnt, 35),
1087a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_octets_bad_cnt, 36),
1097a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_octets_total_filt_cnt, 37),
1107a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_filt_pkt_cnt, 38),
1117a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_trans_pkt_cnt, 39),
1127a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_64, 40),
1137a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_65_127, 41),
1147a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_128_255, 42),
1157a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_256_511, 43),
1167a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_512_1023, 44),
1177a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_1024_1518, 45),
1187a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_framesize_bt_1518, 46),
1197a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_fcs_error_cnt, 47),
1207a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_data_error_cnt, 48),
1217a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_align_error_cnt, 49),
1227a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_frame_long_err_cnt, 50),
1237a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_jabber_err_cnt, 51),
1247a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_pause_macctl_frame_cnt, 52),
1257a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_unknown_macctl_frame_cnt, 53),
1267a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_frame_very_long_err_cnt, 54),
1277a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_frame_runt_err_cnt, 55),
1287a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_frame_short_err_cnt, 56),
1297a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_overflow_cnt, 57),
1307a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_bufrq_err_cnt, 58),
1317a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_we_err_cnt, 59),
1327a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_overrun_cnt, 60),
1337a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_lengthfield_err_cnt, 61),
1347a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_fail_comma_cnt, 62),
1357a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_dma_err_cnt, 63),
1367a5d60dcSJijie Shao HBG_PUSH_STATS_I(rx_fifo_less_empty_thrsld_cnt, 64),
1377a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_octets_total_ok_cnt, 65),
1387a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_uc_pkt_cnt, 66),
1397a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_mc_pkt_cnt, 67),
1407a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_bc_pkt_cnt, 68),
1417a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_vlan_pkt_cnt, 69),
1427a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_octets_bad_cnt, 70),
1437a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_trans_pkt_cnt, 71),
1447a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_pause_frame_cnt, 72),
1457a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_64, 73),
1467a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_65_127, 74),
1477a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_128_255, 75),
1487a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_256_511, 76),
1497a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_512_1023, 77),
1507a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_1024_1518, 78),
1517a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_framesize_bt_1518, 79),
1527a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_underrun_err_cnt, 80),
1537a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_add_cs_fail_cnt, 81),
1547a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_bufrl_err_cnt, 82),
1557a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_crc_err_cnt, 83),
1567a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_drop_cnt, 84),
1577a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_excessive_length_drop_cnt, 85),
1587a5d60dcSJijie Shao HBG_PUSH_STATS_I(tx_dma_err_cnt, 86),
1597a5d60dcSJijie Shao };
1607a5d60dcSJijie Shao
hbg_push_msg_send(struct hbg_priv * priv,struct hbg_diagnose_message * msg)1617a5d60dcSJijie Shao static int hbg_push_msg_send(struct hbg_priv *priv,
1627a5d60dcSJijie Shao struct hbg_diagnose_message *msg)
1637a5d60dcSJijie Shao {
1647a5d60dcSJijie Shao u32 header = 0;
1657a5d60dcSJijie Shao u32 i;
1667a5d60dcSJijie Shao
1677a5d60dcSJijie Shao if (msg->data_num == 0)
1687a5d60dcSJijie Shao return 0;
1697a5d60dcSJijie Shao
1707a5d60dcSJijie Shao for (i = 0; i < msg->data_num && i < HBG_MSG_DATA_MAX_NUM; i++)
1717a5d60dcSJijie Shao hbg_reg_write(priv,
1727a5d60dcSJijie Shao HBG_REG_MSG_DATA_BASE_ADDR + i * sizeof(u32),
1737a5d60dcSJijie Shao msg->data[i]);
1747a5d60dcSJijie Shao
1757a5d60dcSJijie Shao hbg_field_modify(header, HBG_REG_MSG_HEADER_OPCODE_M, msg->opcode);
1767a5d60dcSJijie Shao hbg_field_modify(header, HBG_REG_MSG_HEADER_DATA_NUM_M, msg->data_num);
1777a5d60dcSJijie Shao hbg_field_modify(header, HBG_REG_MSG_HEADER_RESP_CODE_M, ETIMEDOUT);
1787a5d60dcSJijie Shao
1797a5d60dcSJijie Shao /* start status */
1807a5d60dcSJijie Shao hbg_field_modify(header, HBG_REG_MSG_HEADER_STATUS_M, 1);
1817a5d60dcSJijie Shao
1827a5d60dcSJijie Shao /* write header msg to start push */
1837a5d60dcSJijie Shao hbg_reg_write(priv, HBG_REG_MSG_HEADER_ADDR, header);
1847a5d60dcSJijie Shao
1857a5d60dcSJijie Shao /* wait done */
1867a5d60dcSJijie Shao readl_poll_timeout(priv->io_base + HBG_REG_MSG_HEADER_ADDR, header,
1877a5d60dcSJijie Shao !FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header),
1887a5d60dcSJijie Shao HBG_HW_PUSH_WAIT_INTERVAL_US,
1897a5d60dcSJijie Shao HBG_HW_PUSH_WAIT_TIMEOUT_US);
1907a5d60dcSJijie Shao
1917a5d60dcSJijie Shao msg->status = FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header);
1927a5d60dcSJijie Shao return -(int)FIELD_GET(HBG_REG_MSG_HEADER_RESP_CODE_M, header);
1937a5d60dcSJijie Shao }
1947a5d60dcSJijie Shao
hbg_push_data(struct hbg_priv * priv,u32 opcode,u32 * data,u32 data_num)1957a5d60dcSJijie Shao static int hbg_push_data(struct hbg_priv *priv,
1967a5d60dcSJijie Shao u32 opcode, u32 *data, u32 data_num)
1977a5d60dcSJijie Shao {
1987a5d60dcSJijie Shao struct hbg_diagnose_message msg = {0};
1997a5d60dcSJijie Shao u32 data_left_num;
2007a5d60dcSJijie Shao u32 i, j;
2017a5d60dcSJijie Shao int ret;
2027a5d60dcSJijie Shao
2037a5d60dcSJijie Shao msg.priv = priv;
2047a5d60dcSJijie Shao msg.opcode = opcode;
2057a5d60dcSJijie Shao for (i = 0; i < data_num / HBG_MSG_DATA_MAX_NUM + 1; i++) {
2067a5d60dcSJijie Shao if (i * HBG_MSG_DATA_MAX_NUM >= data_num)
2077a5d60dcSJijie Shao break;
2087a5d60dcSJijie Shao
2097a5d60dcSJijie Shao data_left_num = data_num - i * HBG_MSG_DATA_MAX_NUM;
2107a5d60dcSJijie Shao for (j = 0; j < data_left_num && j < HBG_MSG_DATA_MAX_NUM; j++)
2117a5d60dcSJijie Shao msg.data[j] = data[i * HBG_MSG_DATA_MAX_NUM + j];
2127a5d60dcSJijie Shao
2137a5d60dcSJijie Shao msg.data_num = j;
2147a5d60dcSJijie Shao ret = hbg_push_msg_send(priv, &msg);
2157a5d60dcSJijie Shao if (ret)
2167a5d60dcSJijie Shao return ret;
2177a5d60dcSJijie Shao }
2187a5d60dcSJijie Shao
2197a5d60dcSJijie Shao return 0;
2207a5d60dcSJijie Shao }
2217a5d60dcSJijie Shao
hbg_push_data_u64(struct hbg_priv * priv,u32 opcode,u64 * data,u32 data_num)2227a5d60dcSJijie Shao static int hbg_push_data_u64(struct hbg_priv *priv, u32 opcode,
2237a5d60dcSJijie Shao u64 *data, u32 data_num)
2247a5d60dcSJijie Shao {
2257a5d60dcSJijie Shao /* The length of u64 is twice that of u32,
2267a5d60dcSJijie Shao * the data_num must be multiplied by 2.
2277a5d60dcSJijie Shao */
2287a5d60dcSJijie Shao return hbg_push_data(priv, opcode, (u32 *)data, data_num * 2);
2297a5d60dcSJijie Shao }
2307a5d60dcSJijie Shao
hbg_get_irq_stats(struct hbg_vector * vectors,u32 mask)2317a5d60dcSJijie Shao static u64 hbg_get_irq_stats(struct hbg_vector *vectors, u32 mask)
2327a5d60dcSJijie Shao {
2337a5d60dcSJijie Shao u32 i = 0;
2347a5d60dcSJijie Shao
2357a5d60dcSJijie Shao for (i = 0; i < vectors->info_array_len; i++)
2367a5d60dcSJijie Shao if (vectors->info_array[i].mask == mask)
237*4ad3df75SJijie Shao return vectors->stats_array[i];
2387a5d60dcSJijie Shao
2397a5d60dcSJijie Shao return 0;
2407a5d60dcSJijie Shao }
2417a5d60dcSJijie Shao
hbg_push_irq_cnt(struct hbg_priv * priv)2427a5d60dcSJijie Shao static int hbg_push_irq_cnt(struct hbg_priv *priv)
2437a5d60dcSJijie Shao {
2447a5d60dcSJijie Shao /* An id needs to be added for each data.
2457a5d60dcSJijie Shao * Therefore, the data_num must be multiplied by 2.
2467a5d60dcSJijie Shao */
2477a5d60dcSJijie Shao u32 data_num = ARRAY_SIZE(hbg_push_irq_list) * 2;
2487a5d60dcSJijie Shao struct hbg_vector *vectors = &priv->vectors;
2497a5d60dcSJijie Shao const struct hbg_push_irq_info *info;
2507a5d60dcSJijie Shao u32 i, j = 0;
2517a5d60dcSJijie Shao u64 *data;
2527a5d60dcSJijie Shao int ret;
2537a5d60dcSJijie Shao
2547a5d60dcSJijie Shao data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
2557a5d60dcSJijie Shao if (!data)
2567a5d60dcSJijie Shao return -ENOMEM;
2577a5d60dcSJijie Shao
2587a5d60dcSJijie Shao /* An id needs to be added for each data.
2597a5d60dcSJijie Shao * So i + 2 for each loop.
2607a5d60dcSJijie Shao */
2617a5d60dcSJijie Shao for (i = 0; i < data_num; i += 2) {
2627a5d60dcSJijie Shao info = &hbg_push_irq_list[j++];
2637a5d60dcSJijie Shao data[i] = info->id;
2647a5d60dcSJijie Shao data[i + 1] = hbg_get_irq_stats(vectors, info->mask);
2657a5d60dcSJijie Shao }
2667a5d60dcSJijie Shao
2677a5d60dcSJijie Shao ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_IRQ, data, data_num);
2687a5d60dcSJijie Shao kfree(data);
2697a5d60dcSJijie Shao return ret;
2707a5d60dcSJijie Shao }
2717a5d60dcSJijie Shao
hbg_push_link_status(struct hbg_priv * priv)2727a5d60dcSJijie Shao static int hbg_push_link_status(struct hbg_priv *priv)
2737a5d60dcSJijie Shao {
2747a5d60dcSJijie Shao u32 link_status[2];
2757a5d60dcSJijie Shao
2767a5d60dcSJijie Shao /* phy link status */
2777a5d60dcSJijie Shao link_status[0] = priv->mac.phydev->link;
2787a5d60dcSJijie Shao /* mac link status */
2797a5d60dcSJijie Shao link_status[1] = hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
2807a5d60dcSJijie Shao HBG_REG_AN_NEG_STATE_NP_LINK_OK_B);
2817a5d60dcSJijie Shao
2827a5d60dcSJijie Shao return hbg_push_data(priv, HBG_PUSH_CMD_LINK,
2837a5d60dcSJijie Shao link_status, ARRAY_SIZE(link_status));
2847a5d60dcSJijie Shao }
2857a5d60dcSJijie Shao
hbg_push_stats(struct hbg_priv * priv)2867a5d60dcSJijie Shao static int hbg_push_stats(struct hbg_priv *priv)
2877a5d60dcSJijie Shao {
2887a5d60dcSJijie Shao /* An id needs to be added for each data.
2897a5d60dcSJijie Shao * Therefore, the data_num must be multiplied by 2.
2907a5d60dcSJijie Shao */
2917a5d60dcSJijie Shao u64 data_num = ARRAY_SIZE(hbg_push_stats_list) * 2;
2927a5d60dcSJijie Shao struct hbg_stats *stats = &priv->stats;
2937a5d60dcSJijie Shao const struct hbg_push_stats_info *info;
2947a5d60dcSJijie Shao u32 i, j = 0;
2957a5d60dcSJijie Shao u64 *data;
2967a5d60dcSJijie Shao int ret;
2977a5d60dcSJijie Shao
2987a5d60dcSJijie Shao data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
2997a5d60dcSJijie Shao if (!data)
3007a5d60dcSJijie Shao return -ENOMEM;
3017a5d60dcSJijie Shao
3027a5d60dcSJijie Shao /* An id needs to be added for each data.
3037a5d60dcSJijie Shao * So i + 2 for each loop.
3047a5d60dcSJijie Shao */
3057a5d60dcSJijie Shao for (i = 0; i < data_num; i += 2) {
3067a5d60dcSJijie Shao info = &hbg_push_stats_list[j++];
3077a5d60dcSJijie Shao data[i] = info->id;
3087a5d60dcSJijie Shao data[i + 1] = HBG_STATS_R(stats, info->offset);
3097a5d60dcSJijie Shao }
3107a5d60dcSJijie Shao
3117a5d60dcSJijie Shao ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_STATS, data, data_num);
3127a5d60dcSJijie Shao kfree(data);
3137a5d60dcSJijie Shao return ret;
3147a5d60dcSJijie Shao }
3157a5d60dcSJijie Shao
hbg_diagnose_message_push(struct hbg_priv * priv)3167a5d60dcSJijie Shao void hbg_diagnose_message_push(struct hbg_priv *priv)
3177a5d60dcSJijie Shao {
3187a5d60dcSJijie Shao int ret;
3197a5d60dcSJijie Shao
3207a5d60dcSJijie Shao if (test_bit(HBG_NIC_STATE_RESETTING, &priv->state))
3217a5d60dcSJijie Shao return;
3227a5d60dcSJijie Shao
3237a5d60dcSJijie Shao /* only 1 is the right value */
3247a5d60dcSJijie Shao if (hbg_reg_read(priv, HBG_REG_PUSH_REQ_ADDR) != 1)
3257a5d60dcSJijie Shao return;
3267a5d60dcSJijie Shao
3277a5d60dcSJijie Shao ret = hbg_push_irq_cnt(priv);
3287a5d60dcSJijie Shao if (ret) {
3297a5d60dcSJijie Shao dev_err(&priv->pdev->dev,
3307a5d60dcSJijie Shao "failed to push irq cnt, ret = %d\n", ret);
3317a5d60dcSJijie Shao goto push_done;
3327a5d60dcSJijie Shao }
3337a5d60dcSJijie Shao
3347a5d60dcSJijie Shao ret = hbg_push_link_status(priv);
3357a5d60dcSJijie Shao if (ret) {
3367a5d60dcSJijie Shao dev_err(&priv->pdev->dev,
3377a5d60dcSJijie Shao "failed to push link status, ret = %d\n", ret);
3387a5d60dcSJijie Shao goto push_done;
3397a5d60dcSJijie Shao }
3407a5d60dcSJijie Shao
3417a5d60dcSJijie Shao ret = hbg_push_stats(priv);
3427a5d60dcSJijie Shao if (ret)
3437a5d60dcSJijie Shao dev_err(&priv->pdev->dev,
3447a5d60dcSJijie Shao "failed to push stats, ret = %d\n", ret);
3457a5d60dcSJijie Shao
3467a5d60dcSJijie Shao push_done:
3477a5d60dcSJijie Shao hbg_reg_write(priv, HBG_REG_PUSH_REQ_ADDR, 0);
3487a5d60dcSJijie Shao }
349