1a95ac4f9SJijie Shao // SPDX-License-Identifier: GPL-2.0+
2a95ac4f9SJijie Shao // Copyright (c) 2024 Hisilicon Limited.
3a95ac4f9SJijie Shao
4a95ac4f9SJijie Shao #include <linux/etherdevice.h>
5ff4edac6SJijie Shao #include <linux/if_vlan.h>
6a95ac4f9SJijie Shao #include <linux/netdevice.h>
7a95ac4f9SJijie Shao #include <linux/pci.h>
8615552c6SJijie Shao #include <linux/phy.h>
9a95ac4f9SJijie Shao #include "hbg_common.h"
107a5d60dcSJijie Shao #include "hbg_diagnose.h"
113f5a61f6SJijie Shao #include "hbg_err.h"
12e8d13548SJijie Shao #include "hbg_ethtool.h"
13fc1992baSJijie Shao #include "hbg_hw.h"
144d089035SJijie Shao #include "hbg_irq.h"
15a239b2b1SJijie Shao #include "hbg_mdio.h"
1640735e75SJijie Shao #include "hbg_txrx.h"
1786331b51SJijie Shao #include "hbg_debugfs.h"
1840735e75SJijie Shao
19833b65a3SJijie Shao #define HBG_SUPPORT_FEATURES (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
20833b65a3SJijie Shao NETIF_F_RXCSUM)
21833b65a3SJijie Shao
hbg_all_irq_enable(struct hbg_priv * priv,bool enabled)22ff4edac6SJijie Shao static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
23ff4edac6SJijie Shao {
244ad3df75SJijie Shao const struct hbg_irq_info *info;
25ff4edac6SJijie Shao u32 i;
26ff4edac6SJijie Shao
27ff4edac6SJijie Shao for (i = 0; i < priv->vectors.info_array_len; i++) {
28ff4edac6SJijie Shao info = &priv->vectors.info_array[i];
29ff4edac6SJijie Shao hbg_hw_irq_enable(priv, info->mask, enabled);
30ff4edac6SJijie Shao }
31ff4edac6SJijie Shao }
32ff4edac6SJijie Shao
hbg_net_open(struct net_device * netdev)33ff4edac6SJijie Shao static int hbg_net_open(struct net_device *netdev)
34ff4edac6SJijie Shao {
35ff4edac6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
3640735e75SJijie Shao int ret;
3740735e75SJijie Shao
3840735e75SJijie Shao ret = hbg_txrx_init(priv);
3940735e75SJijie Shao if (ret)
4040735e75SJijie Shao return ret;
41ff4edac6SJijie Shao
42ff4edac6SJijie Shao hbg_all_irq_enable(priv, true);
43ff4edac6SJijie Shao hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
44ff4edac6SJijie Shao netif_start_queue(netdev);
45ff4edac6SJijie Shao hbg_phy_start(priv);
46ff4edac6SJijie Shao
47ff4edac6SJijie Shao return 0;
48ff4edac6SJijie Shao }
49ff4edac6SJijie Shao
5040735e75SJijie Shao /* This function only can be called after hbg_txrx_uninit() */
hbg_hw_txrx_clear(struct hbg_priv * priv)5140735e75SJijie Shao static int hbg_hw_txrx_clear(struct hbg_priv *priv)
5240735e75SJijie Shao {
5340735e75SJijie Shao int ret;
5440735e75SJijie Shao
5540735e75SJijie Shao /* After ring buffers have been released,
5640735e75SJijie Shao * do a reset to release hw fifo rx ring buffer
5740735e75SJijie Shao */
5840735e75SJijie Shao ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
5940735e75SJijie Shao if (ret)
6040735e75SJijie Shao return ret;
6140735e75SJijie Shao
6240735e75SJijie Shao /* After reset, regs need to be reconfigured */
633f5a61f6SJijie Shao return hbg_rebuild(priv);
6440735e75SJijie Shao }
6540735e75SJijie Shao
hbg_net_stop(struct net_device * netdev)66ff4edac6SJijie Shao static int hbg_net_stop(struct net_device *netdev)
67ff4edac6SJijie Shao {
68ff4edac6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
69ff4edac6SJijie Shao
70ff4edac6SJijie Shao hbg_phy_stop(priv);
71ff4edac6SJijie Shao netif_stop_queue(netdev);
72ff4edac6SJijie Shao hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
73ff4edac6SJijie Shao hbg_all_irq_enable(priv, false);
7440735e75SJijie Shao hbg_txrx_uninit(priv);
7540735e75SJijie Shao return hbg_hw_txrx_clear(priv);
76ff4edac6SJijie Shao }
77ff4edac6SJijie Shao
hbg_update_promisc_mode(struct net_device * netdev,bool overflow)7837b367d6SJijie Shao static void hbg_update_promisc_mode(struct net_device *netdev, bool overflow)
7937b367d6SJijie Shao {
8037b367d6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
8137b367d6SJijie Shao
8237b367d6SJijie Shao /* Only when not table_overflow, and netdev->flags not set IFF_PROMISC,
8337b367d6SJijie Shao * The MAC filter will be enabled.
8437b367d6SJijie Shao * Otherwise the filter will be disabled.
8537b367d6SJijie Shao */
8637b367d6SJijie Shao priv->filter.enabled = !(overflow || (netdev->flags & IFF_PROMISC));
8737b367d6SJijie Shao hbg_hw_set_mac_filter_enable(priv, priv->filter.enabled);
8837b367d6SJijie Shao }
8937b367d6SJijie Shao
hbg_set_mac_to_mac_table(struct hbg_priv * priv,u32 index,const u8 * addr)9037b367d6SJijie Shao static void hbg_set_mac_to_mac_table(struct hbg_priv *priv,
9137b367d6SJijie Shao u32 index, const u8 *addr)
9237b367d6SJijie Shao {
9337b367d6SJijie Shao if (addr) {
9437b367d6SJijie Shao ether_addr_copy(priv->filter.mac_table[index].addr, addr);
9537b367d6SJijie Shao hbg_hw_set_uc_addr(priv, ether_addr_to_u64(addr), index);
9637b367d6SJijie Shao } else {
9737b367d6SJijie Shao eth_zero_addr(priv->filter.mac_table[index].addr);
9837b367d6SJijie Shao hbg_hw_set_uc_addr(priv, 0, index);
9937b367d6SJijie Shao }
10037b367d6SJijie Shao }
10137b367d6SJijie Shao
hbg_get_index_from_mac_table(struct hbg_priv * priv,const u8 * addr,u32 * index)10237b367d6SJijie Shao static int hbg_get_index_from_mac_table(struct hbg_priv *priv,
10337b367d6SJijie Shao const u8 *addr, u32 *index)
10437b367d6SJijie Shao {
10537b367d6SJijie Shao u32 i;
10637b367d6SJijie Shao
10737b367d6SJijie Shao for (i = 0; i < priv->filter.table_max_len; i++)
10837b367d6SJijie Shao if (ether_addr_equal(priv->filter.mac_table[i].addr, addr)) {
10937b367d6SJijie Shao *index = i;
11037b367d6SJijie Shao return 0;
11137b367d6SJijie Shao }
11237b367d6SJijie Shao
11337b367d6SJijie Shao return -EINVAL;
11437b367d6SJijie Shao }
11537b367d6SJijie Shao
hbg_add_mac_to_filter(struct hbg_priv * priv,const u8 * addr)11637b367d6SJijie Shao static int hbg_add_mac_to_filter(struct hbg_priv *priv, const u8 *addr)
11737b367d6SJijie Shao {
11837b367d6SJijie Shao u32 index;
11937b367d6SJijie Shao
12037b367d6SJijie Shao /* already exists */
12137b367d6SJijie Shao if (!hbg_get_index_from_mac_table(priv, addr, &index))
12237b367d6SJijie Shao return 0;
12337b367d6SJijie Shao
12437b367d6SJijie Shao for (index = 0; index < priv->filter.table_max_len; index++)
12537b367d6SJijie Shao if (is_zero_ether_addr(priv->filter.mac_table[index].addr)) {
12637b367d6SJijie Shao hbg_set_mac_to_mac_table(priv, index, addr);
12737b367d6SJijie Shao return 0;
12837b367d6SJijie Shao }
12937b367d6SJijie Shao
13037b367d6SJijie Shao return -ENOSPC;
13137b367d6SJijie Shao }
13237b367d6SJijie Shao
hbg_del_mac_from_filter(struct hbg_priv * priv,const u8 * addr)13337b367d6SJijie Shao static void hbg_del_mac_from_filter(struct hbg_priv *priv, const u8 *addr)
13437b367d6SJijie Shao {
13537b367d6SJijie Shao u32 index;
13637b367d6SJijie Shao
13737b367d6SJijie Shao /* not exists */
13837b367d6SJijie Shao if (hbg_get_index_from_mac_table(priv, addr, &index))
13937b367d6SJijie Shao return;
14037b367d6SJijie Shao
14137b367d6SJijie Shao hbg_set_mac_to_mac_table(priv, index, NULL);
14237b367d6SJijie Shao }
14337b367d6SJijie Shao
hbg_uc_sync(struct net_device * netdev,const unsigned char * addr)14437b367d6SJijie Shao static int hbg_uc_sync(struct net_device *netdev, const unsigned char *addr)
14537b367d6SJijie Shao {
14637b367d6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
14737b367d6SJijie Shao
14837b367d6SJijie Shao return hbg_add_mac_to_filter(priv, addr);
14937b367d6SJijie Shao }
15037b367d6SJijie Shao
hbg_uc_unsync(struct net_device * netdev,const unsigned char * addr)15137b367d6SJijie Shao static int hbg_uc_unsync(struct net_device *netdev, const unsigned char *addr)
15237b367d6SJijie Shao {
15337b367d6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
15437b367d6SJijie Shao
15537b367d6SJijie Shao if (ether_addr_equal(netdev->dev_addr, (u8 *)addr))
15637b367d6SJijie Shao return 0;
15737b367d6SJijie Shao
15837b367d6SJijie Shao hbg_del_mac_from_filter(priv, addr);
15937b367d6SJijie Shao return 0;
16037b367d6SJijie Shao }
16137b367d6SJijie Shao
hbg_net_set_rx_mode(struct net_device * netdev)16237b367d6SJijie Shao static void hbg_net_set_rx_mode(struct net_device *netdev)
16337b367d6SJijie Shao {
16437b367d6SJijie Shao int ret;
16537b367d6SJijie Shao
16637b367d6SJijie Shao ret = __dev_uc_sync(netdev, hbg_uc_sync, hbg_uc_unsync);
16737b367d6SJijie Shao
16837b367d6SJijie Shao /* If ret != 0, overflow has occurred */
16937b367d6SJijie Shao hbg_update_promisc_mode(netdev, !!ret);
17037b367d6SJijie Shao }
17137b367d6SJijie Shao
hbg_net_set_mac_address(struct net_device * netdev,void * addr)172ff4edac6SJijie Shao static int hbg_net_set_mac_address(struct net_device *netdev, void *addr)
173ff4edac6SJijie Shao {
174ff4edac6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
175ff4edac6SJijie Shao u8 *mac_addr;
17637b367d6SJijie Shao bool exists;
17737b367d6SJijie Shao u32 index;
178ff4edac6SJijie Shao
179ff4edac6SJijie Shao mac_addr = ((struct sockaddr *)addr)->sa_data;
180ff4edac6SJijie Shao
181ff4edac6SJijie Shao if (!is_valid_ether_addr(mac_addr))
182ff4edac6SJijie Shao return -EADDRNOTAVAIL;
183ff4edac6SJijie Shao
18437b367d6SJijie Shao /* The index of host mac is always 0.
18537b367d6SJijie Shao * If new mac address already exists,
18637b367d6SJijie Shao * delete the existing mac address and
18737b367d6SJijie Shao * add it to the position with index 0.
18837b367d6SJijie Shao */
18937b367d6SJijie Shao exists = !hbg_get_index_from_mac_table(priv, mac_addr, &index);
19037b367d6SJijie Shao hbg_set_mac_to_mac_table(priv, 0, mac_addr);
19137b367d6SJijie Shao if (exists)
19237b367d6SJijie Shao hbg_set_mac_to_mac_table(priv, index, NULL);
193ff4edac6SJijie Shao
1943a03763fSJijie Shao hbg_hw_set_rx_pause_mac_addr(priv, ether_addr_to_u64(mac_addr));
19537b367d6SJijie Shao dev_addr_set(netdev, mac_addr);
196ff4edac6SJijie Shao return 0;
197ff4edac6SJijie Shao }
198ff4edac6SJijie Shao
hbg_net_change_mtu(struct net_device * netdev,int new_mtu)199ff4edac6SJijie Shao static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu)
200ff4edac6SJijie Shao {
201ff4edac6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
202ff4edac6SJijie Shao
203ff4edac6SJijie Shao if (netif_running(netdev))
204ff4edac6SJijie Shao return -EBUSY;
205ff4edac6SJijie Shao
206ff4edac6SJijie Shao dev_dbg(&priv->pdev->dev,
207ff4edac6SJijie Shao "change mtu from %u to %u\n", netdev->mtu, new_mtu);
208ff4edac6SJijie Shao
209*4e4ac533SJijie Shao hbg_hw_set_mtu(priv, new_mtu);
210*4e4ac533SJijie Shao WRITE_ONCE(netdev->mtu, new_mtu);
211*4e4ac533SJijie Shao
212ff4edac6SJijie Shao return 0;
213ff4edac6SJijie Shao }
214ff4edac6SJijie Shao
hbg_net_tx_timeout(struct net_device * netdev,unsigned int txqueue)21540735e75SJijie Shao static void hbg_net_tx_timeout(struct net_device *netdev, unsigned int txqueue)
21640735e75SJijie Shao {
21740735e75SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
21840735e75SJijie Shao struct hbg_ring *ring = &priv->tx_ring;
21940735e75SJijie Shao char *buf = ring->tout_log_buf;
22040735e75SJijie Shao u32 pos = 0;
22140735e75SJijie Shao
222c0bf9bf3SJijie Shao priv->stats.tx_timeout_cnt++;
223c0bf9bf3SJijie Shao
224c0bf9bf3SJijie Shao pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
225c0bf9bf3SJijie Shao "tx_timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);
22640735e75SJijie Shao pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
22740735e75SJijie Shao "ring used num: %u, fifo used num: %u\n",
22840735e75SJijie Shao hbg_get_queue_used_num(ring),
22940735e75SJijie Shao hbg_hw_get_fifo_used_num(priv, HBG_DIR_TX));
23040735e75SJijie Shao pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
23140735e75SJijie Shao "ntc: %u, ntu: %u, irq enabled: %u\n",
23240735e75SJijie Shao ring->ntc, ring->ntu,
23340735e75SJijie Shao hbg_hw_irq_is_enabled(priv, HBG_INT_MSK_TX_B));
23440735e75SJijie Shao
23540735e75SJijie Shao netdev_info(netdev, "%s", buf);
23640735e75SJijie Shao }
23740735e75SJijie Shao
hbg_net_get_stats(struct net_device * netdev,struct rtnl_link_stats64 * stats)238c0bf9bf3SJijie Shao static void hbg_net_get_stats(struct net_device *netdev,
239c0bf9bf3SJijie Shao struct rtnl_link_stats64 *stats)
240c0bf9bf3SJijie Shao {
241c0bf9bf3SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
242c0bf9bf3SJijie Shao struct hbg_stats *h_stats = &priv->stats;
243c0bf9bf3SJijie Shao
244c0bf9bf3SJijie Shao hbg_update_stats(priv);
245c0bf9bf3SJijie Shao dev_get_tstats64(netdev, stats);
246c0bf9bf3SJijie Shao
247c0bf9bf3SJijie Shao /* fifo empty */
248c0bf9bf3SJijie Shao stats->tx_fifo_errors += h_stats->tx_drop_cnt;
249c0bf9bf3SJijie Shao
250c0bf9bf3SJijie Shao stats->tx_dropped += h_stats->tx_excessive_length_drop_cnt +
251c0bf9bf3SJijie Shao h_stats->tx_drop_cnt;
252c0bf9bf3SJijie Shao stats->tx_errors += h_stats->tx_add_cs_fail_cnt +
253c0bf9bf3SJijie Shao h_stats->tx_bufrl_err_cnt +
254c0bf9bf3SJijie Shao h_stats->tx_underrun_err_cnt +
255c0bf9bf3SJijie Shao h_stats->tx_crc_err_cnt;
256c0bf9bf3SJijie Shao stats->rx_errors += h_stats->rx_data_error_cnt;
257c0bf9bf3SJijie Shao stats->multicast += h_stats->rx_mc_pkt_cnt;
258c0bf9bf3SJijie Shao stats->rx_dropped += h_stats->rx_desc_drop;
259c0bf9bf3SJijie Shao stats->rx_length_errors += h_stats->rx_frame_very_long_err_cnt +
260c0bf9bf3SJijie Shao h_stats->rx_frame_long_err_cnt +
261c0bf9bf3SJijie Shao h_stats->rx_frame_runt_err_cnt +
262c0bf9bf3SJijie Shao h_stats->rx_frame_short_err_cnt +
263c0bf9bf3SJijie Shao h_stats->rx_lengthfield_err_cnt;
264c0bf9bf3SJijie Shao stats->rx_frame_errors += h_stats->rx_desc_l2_err_cnt +
265c0bf9bf3SJijie Shao h_stats->rx_desc_l3l4_err_cnt;
266c0bf9bf3SJijie Shao stats->rx_fifo_errors += h_stats->rx_overflow_cnt +
267c0bf9bf3SJijie Shao h_stats->rx_overrun_cnt;
268c0bf9bf3SJijie Shao stats->rx_crc_errors += h_stats->rx_fcs_error_cnt;
269c0bf9bf3SJijie Shao }
270c0bf9bf3SJijie Shao
271ff4edac6SJijie Shao static const struct net_device_ops hbg_netdev_ops = {
272ff4edac6SJijie Shao .ndo_open = hbg_net_open,
273ff4edac6SJijie Shao .ndo_stop = hbg_net_stop,
27440735e75SJijie Shao .ndo_start_xmit = hbg_net_start_xmit,
275ff4edac6SJijie Shao .ndo_validate_addr = eth_validate_addr,
276ff4edac6SJijie Shao .ndo_set_mac_address = hbg_net_set_mac_address,
277ff4edac6SJijie Shao .ndo_change_mtu = hbg_net_change_mtu,
27840735e75SJijie Shao .ndo_tx_timeout = hbg_net_tx_timeout,
27937b367d6SJijie Shao .ndo_set_rx_mode = hbg_net_set_rx_mode,
280c0bf9bf3SJijie Shao .ndo_get_stats64 = hbg_net_get_stats,
281615552c6SJijie Shao .ndo_eth_ioctl = phy_do_ioctl_running,
282ff4edac6SJijie Shao };
283ff4edac6SJijie Shao
hbg_service_task(struct work_struct * work)284c0bf9bf3SJijie Shao static void hbg_service_task(struct work_struct *work)
285c0bf9bf3SJijie Shao {
286c0bf9bf3SJijie Shao struct hbg_priv *priv = container_of(work, struct hbg_priv,
287c0bf9bf3SJijie Shao service_task.work);
288c0bf9bf3SJijie Shao
289fd394a33SJijie Shao if (test_and_clear_bit(HBG_NIC_STATE_NEED_RESET, &priv->state))
290fd394a33SJijie Shao hbg_err_reset(priv);
291fd394a33SJijie Shao
292e0306637SJijie Shao if (test_and_clear_bit(HBG_NIC_STATE_NP_LINK_FAIL, &priv->state))
293e0306637SJijie Shao hbg_fix_np_link_fail(priv);
294e0306637SJijie Shao
2957a5d60dcSJijie Shao hbg_diagnose_message_push(priv);
2967a5d60dcSJijie Shao
297c0bf9bf3SJijie Shao /* The type of statistics register is u32,
298c0bf9bf3SJijie Shao * To prevent the statistics register from overflowing,
299c0bf9bf3SJijie Shao * the driver dumps the statistics every 30 seconds.
300c0bf9bf3SJijie Shao */
3017a5d60dcSJijie Shao if (time_after(jiffies, priv->last_update_stats_time + 30 * HZ)) {
302c0bf9bf3SJijie Shao hbg_update_stats(priv);
3037a5d60dcSJijie Shao priv->last_update_stats_time = jiffies;
3047a5d60dcSJijie Shao }
3057a5d60dcSJijie Shao
306c0bf9bf3SJijie Shao schedule_delayed_work(&priv->service_task,
3077a5d60dcSJijie Shao msecs_to_jiffies(MSEC_PER_SEC));
308c0bf9bf3SJijie Shao }
309c0bf9bf3SJijie Shao
hbg_err_reset_task_schedule(struct hbg_priv * priv)310fd394a33SJijie Shao void hbg_err_reset_task_schedule(struct hbg_priv *priv)
311fd394a33SJijie Shao {
312fd394a33SJijie Shao set_bit(HBG_NIC_STATE_NEED_RESET, &priv->state);
313fd394a33SJijie Shao schedule_delayed_work(&priv->service_task, 0);
314fd394a33SJijie Shao }
315fd394a33SJijie Shao
hbg_np_link_fail_task_schedule(struct hbg_priv * priv)316e0306637SJijie Shao void hbg_np_link_fail_task_schedule(struct hbg_priv *priv)
317e0306637SJijie Shao {
318e0306637SJijie Shao set_bit(HBG_NIC_STATE_NP_LINK_FAIL, &priv->state);
319e0306637SJijie Shao schedule_delayed_work(&priv->service_task, 0);
320e0306637SJijie Shao }
321e0306637SJijie Shao
hbg_cancel_delayed_work_sync(void * data)322c0bf9bf3SJijie Shao static void hbg_cancel_delayed_work_sync(void *data)
323c0bf9bf3SJijie Shao {
324c0bf9bf3SJijie Shao cancel_delayed_work_sync(data);
325c0bf9bf3SJijie Shao }
326c0bf9bf3SJijie Shao
hbg_delaywork_init(struct hbg_priv * priv)327c0bf9bf3SJijie Shao static int hbg_delaywork_init(struct hbg_priv *priv)
328c0bf9bf3SJijie Shao {
329c0bf9bf3SJijie Shao INIT_DELAYED_WORK(&priv->service_task, hbg_service_task);
330c0bf9bf3SJijie Shao schedule_delayed_work(&priv->service_task, 0);
331c0bf9bf3SJijie Shao return devm_add_action_or_reset(&priv->pdev->dev,
332c0bf9bf3SJijie Shao hbg_cancel_delayed_work_sync,
333c0bf9bf3SJijie Shao &priv->service_task);
334c0bf9bf3SJijie Shao }
335c0bf9bf3SJijie Shao
hbg_mac_filter_init(struct hbg_priv * priv)33637b367d6SJijie Shao static int hbg_mac_filter_init(struct hbg_priv *priv)
33737b367d6SJijie Shao {
33837b367d6SJijie Shao struct hbg_dev_specs *dev_specs = &priv->dev_specs;
33937b367d6SJijie Shao struct hbg_mac_filter *filter = &priv->filter;
34037b367d6SJijie Shao struct hbg_mac_table_entry *tmp_table;
34137b367d6SJijie Shao
34237b367d6SJijie Shao tmp_table = devm_kcalloc(&priv->pdev->dev, dev_specs->uc_mac_num,
34337b367d6SJijie Shao sizeof(*tmp_table), GFP_KERNEL);
34437b367d6SJijie Shao if (!tmp_table)
34537b367d6SJijie Shao return -ENOMEM;
34637b367d6SJijie Shao
34737b367d6SJijie Shao filter->mac_table = tmp_table;
34837b367d6SJijie Shao filter->table_max_len = dev_specs->uc_mac_num;
34937b367d6SJijie Shao filter->enabled = true;
35037b367d6SJijie Shao
35137b367d6SJijie Shao hbg_hw_set_mac_filter_enable(priv, filter->enabled);
35237b367d6SJijie Shao return 0;
35337b367d6SJijie Shao }
35437b367d6SJijie Shao
hbg_init_user_def(struct hbg_priv * priv)3553f5a61f6SJijie Shao static void hbg_init_user_def(struct hbg_priv *priv)
3563f5a61f6SJijie Shao {
3573f5a61f6SJijie Shao struct ethtool_pauseparam *pause_param = &priv->user_def.pause_param;
3583f5a61f6SJijie Shao
3593f5a61f6SJijie Shao priv->mac.pause_autoneg = HBG_STATUS_ENABLE;
3603f5a61f6SJijie Shao
3613f5a61f6SJijie Shao pause_param->autoneg = priv->mac.pause_autoneg;
3623f5a61f6SJijie Shao hbg_hw_get_pause_enable(priv, &pause_param->tx_pause,
3633f5a61f6SJijie Shao &pause_param->rx_pause);
3643f5a61f6SJijie Shao }
3653f5a61f6SJijie Shao
hbg_init(struct hbg_priv * priv)366fc1992baSJijie Shao static int hbg_init(struct hbg_priv *priv)
367fc1992baSJijie Shao {
368fc1992baSJijie Shao int ret;
369fc1992baSJijie Shao
370fc1992baSJijie Shao ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT);
371fc1992baSJijie Shao if (ret)
372fc1992baSJijie Shao return ret;
373fc1992baSJijie Shao
374a239b2b1SJijie Shao ret = hbg_hw_init(priv);
375a239b2b1SJijie Shao if (ret)
376a239b2b1SJijie Shao return ret;
377a239b2b1SJijie Shao
3784d089035SJijie Shao ret = hbg_irq_init(priv);
3794d089035SJijie Shao if (ret)
3804d089035SJijie Shao return ret;
3814d089035SJijie Shao
38286331b51SJijie Shao ret = hbg_mdio_init(priv);
38386331b51SJijie Shao if (ret)
38486331b51SJijie Shao return ret;
38586331b51SJijie Shao
38637b367d6SJijie Shao ret = hbg_mac_filter_init(priv);
38737b367d6SJijie Shao if (ret)
38837b367d6SJijie Shao return ret;
38937b367d6SJijie Shao
390c0bf9bf3SJijie Shao ret = hbg_delaywork_init(priv);
391c0bf9bf3SJijie Shao if (ret)
392c0bf9bf3SJijie Shao return ret;
393c0bf9bf3SJijie Shao
39486331b51SJijie Shao hbg_debugfs_init(priv);
3953f5a61f6SJijie Shao hbg_init_user_def(priv);
39686331b51SJijie Shao return 0;
397fc1992baSJijie Shao }
398a95ac4f9SJijie Shao
hbg_pci_init(struct pci_dev * pdev)399a95ac4f9SJijie Shao static int hbg_pci_init(struct pci_dev *pdev)
400a95ac4f9SJijie Shao {
401a95ac4f9SJijie Shao struct net_device *netdev = pci_get_drvdata(pdev);
402a95ac4f9SJijie Shao struct hbg_priv *priv = netdev_priv(netdev);
403a95ac4f9SJijie Shao struct device *dev = &pdev->dev;
404a95ac4f9SJijie Shao int ret;
405a95ac4f9SJijie Shao
406a95ac4f9SJijie Shao ret = pcim_enable_device(pdev);
407a95ac4f9SJijie Shao if (ret)
408a95ac4f9SJijie Shao return dev_err_probe(dev, ret, "failed to enable PCI device\n");
409a95ac4f9SJijie Shao
410a95ac4f9SJijie Shao ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
411a95ac4f9SJijie Shao if (ret)
412a95ac4f9SJijie Shao return dev_err_probe(dev, ret, "failed to set PCI DMA mask\n");
413a95ac4f9SJijie Shao
414a95ac4f9SJijie Shao ret = pcim_iomap_regions(pdev, BIT(0), dev_driver_string(dev));
415a95ac4f9SJijie Shao if (ret)
416a95ac4f9SJijie Shao return dev_err_probe(dev, ret, "failed to map PCI bar space\n");
417a95ac4f9SJijie Shao
418a95ac4f9SJijie Shao priv->io_base = pcim_iomap_table(pdev)[0];
419a95ac4f9SJijie Shao if (!priv->io_base)
420a95ac4f9SJijie Shao return dev_err_probe(dev, -ENOMEM, "failed to get io base\n");
421a95ac4f9SJijie Shao
422a95ac4f9SJijie Shao pci_set_master(pdev);
423a95ac4f9SJijie Shao return 0;
424a95ac4f9SJijie Shao }
425a95ac4f9SJijie Shao
hbg_probe(struct pci_dev * pdev,const struct pci_device_id * ent)426a95ac4f9SJijie Shao static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
427a95ac4f9SJijie Shao {
428a95ac4f9SJijie Shao struct device *dev = &pdev->dev;
429a95ac4f9SJijie Shao struct net_device *netdev;
430a95ac4f9SJijie Shao struct hbg_priv *priv;
431a95ac4f9SJijie Shao int ret;
432a95ac4f9SJijie Shao
433a95ac4f9SJijie Shao netdev = devm_alloc_etherdev(dev, sizeof(struct hbg_priv));
434a95ac4f9SJijie Shao if (!netdev)
435a95ac4f9SJijie Shao return -ENOMEM;
436a95ac4f9SJijie Shao
437a95ac4f9SJijie Shao pci_set_drvdata(pdev, netdev);
438a95ac4f9SJijie Shao SET_NETDEV_DEV(netdev, dev);
439a95ac4f9SJijie Shao
440a95ac4f9SJijie Shao priv = netdev_priv(netdev);
441a95ac4f9SJijie Shao priv->netdev = netdev;
442a95ac4f9SJijie Shao priv->pdev = pdev;
443a95ac4f9SJijie Shao
444a95ac4f9SJijie Shao ret = hbg_pci_init(pdev);
445a95ac4f9SJijie Shao if (ret)
446a95ac4f9SJijie Shao return ret;
447a95ac4f9SJijie Shao
448fc1992baSJijie Shao ret = hbg_init(priv);
449fc1992baSJijie Shao if (ret)
450fc1992baSJijie Shao return ret;
451fc1992baSJijie Shao
452833b65a3SJijie Shao /* set default features */
453833b65a3SJijie Shao netdev->features |= HBG_SUPPORT_FEATURES;
454833b65a3SJijie Shao netdev->hw_features |= HBG_SUPPORT_FEATURES;
45537b367d6SJijie Shao netdev->priv_flags |= IFF_UNICAST_FLT;
45637b367d6SJijie Shao
457a95ac4f9SJijie Shao netdev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
458ff4edac6SJijie Shao netdev->max_mtu = priv->dev_specs.max_mtu;
459ff4edac6SJijie Shao netdev->min_mtu = priv->dev_specs.min_mtu;
460ff4edac6SJijie Shao netdev->netdev_ops = &hbg_netdev_ops;
46140735e75SJijie Shao netdev->watchdog_timeo = 5 * HZ;
462ff4edac6SJijie Shao
4633f5a61f6SJijie Shao hbg_hw_set_mtu(priv, ETH_DATA_LEN);
464ff4edac6SJijie Shao hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr);
465e8d13548SJijie Shao hbg_ethtool_set_ops(netdev);
466a95ac4f9SJijie Shao
467a95ac4f9SJijie Shao ret = devm_register_netdev(dev, netdev);
468a95ac4f9SJijie Shao if (ret)
469a95ac4f9SJijie Shao return dev_err_probe(dev, ret, "failed to register netdev\n");
470a95ac4f9SJijie Shao
471a95ac4f9SJijie Shao netif_carrier_off(netdev);
472a95ac4f9SJijie Shao return 0;
473a95ac4f9SJijie Shao }
474a95ac4f9SJijie Shao
475a95ac4f9SJijie Shao static const struct pci_device_id hbg_pci_tbl[] = {
476a95ac4f9SJijie Shao {PCI_VDEVICE(HUAWEI, 0x3730), 0},
477a95ac4f9SJijie Shao { }
478a95ac4f9SJijie Shao };
479a95ac4f9SJijie Shao MODULE_DEVICE_TABLE(pci, hbg_pci_tbl);
480a95ac4f9SJijie Shao
481a95ac4f9SJijie Shao static struct pci_driver hbg_driver = {
482a95ac4f9SJijie Shao .name = "hibmcge",
483a95ac4f9SJijie Shao .id_table = hbg_pci_tbl,
484a95ac4f9SJijie Shao .probe = hbg_probe,
485a95ac4f9SJijie Shao };
48686331b51SJijie Shao
hbg_module_init(void)48786331b51SJijie Shao static int __init hbg_module_init(void)
48886331b51SJijie Shao {
48986331b51SJijie Shao int ret;
49086331b51SJijie Shao
49186331b51SJijie Shao hbg_debugfs_register();
4923f5a61f6SJijie Shao hbg_set_pci_err_handler(&hbg_driver);
49386331b51SJijie Shao ret = pci_register_driver(&hbg_driver);
49486331b51SJijie Shao if (ret)
49586331b51SJijie Shao hbg_debugfs_unregister();
49686331b51SJijie Shao
49786331b51SJijie Shao return ret;
49886331b51SJijie Shao }
49986331b51SJijie Shao module_init(hbg_module_init);
50086331b51SJijie Shao
hbg_module_exit(void)50186331b51SJijie Shao static void __exit hbg_module_exit(void)
50286331b51SJijie Shao {
50386331b51SJijie Shao pci_unregister_driver(&hbg_driver);
50486331b51SJijie Shao hbg_debugfs_unregister();
50586331b51SJijie Shao }
50686331b51SJijie Shao module_exit(hbg_module_exit);
507a95ac4f9SJijie Shao
508a95ac4f9SJijie Shao MODULE_LICENSE("GPL");
509a95ac4f9SJijie Shao MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
510a95ac4f9SJijie Shao MODULE_DESCRIPTION("hibmcge driver");
511a95ac4f9SJijie Shao MODULE_VERSION("1.0");
512