xref: /linux/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
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>
8a95ac4f9SJijie Shao #include "hbg_common.h"
9*e8d13548SJijie Shao #include "hbg_ethtool.h"
10fc1992baSJijie Shao #include "hbg_hw.h"
114d089035SJijie Shao #include "hbg_irq.h"
12a239b2b1SJijie Shao #include "hbg_mdio.h"
1340735e75SJijie Shao #include "hbg_txrx.h"
1440735e75SJijie Shao 
1540735e75SJijie Shao static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu);
16fc1992baSJijie Shao 
17ff4edac6SJijie Shao static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
18ff4edac6SJijie Shao {
19ff4edac6SJijie Shao 	struct hbg_irq_info *info;
20ff4edac6SJijie Shao 	u32 i;
21ff4edac6SJijie Shao 
22ff4edac6SJijie Shao 	for (i = 0; i < priv->vectors.info_array_len; i++) {
23ff4edac6SJijie Shao 		info = &priv->vectors.info_array[i];
24ff4edac6SJijie Shao 		hbg_hw_irq_enable(priv, info->mask, enabled);
25ff4edac6SJijie Shao 	}
26ff4edac6SJijie Shao }
27ff4edac6SJijie Shao 
28ff4edac6SJijie Shao static int hbg_net_open(struct net_device *netdev)
29ff4edac6SJijie Shao {
30ff4edac6SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
3140735e75SJijie Shao 	int ret;
3240735e75SJijie Shao 
3340735e75SJijie Shao 	ret = hbg_txrx_init(priv);
3440735e75SJijie Shao 	if (ret)
3540735e75SJijie Shao 		return ret;
36ff4edac6SJijie Shao 
37ff4edac6SJijie Shao 	hbg_all_irq_enable(priv, true);
38ff4edac6SJijie Shao 	hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
39ff4edac6SJijie Shao 	netif_start_queue(netdev);
40ff4edac6SJijie Shao 	hbg_phy_start(priv);
41ff4edac6SJijie Shao 
42ff4edac6SJijie Shao 	return 0;
43ff4edac6SJijie Shao }
44ff4edac6SJijie Shao 
4540735e75SJijie Shao /* This function only can be called after hbg_txrx_uninit() */
4640735e75SJijie Shao static int hbg_hw_txrx_clear(struct hbg_priv *priv)
4740735e75SJijie Shao {
4840735e75SJijie Shao 	int ret;
4940735e75SJijie Shao 
5040735e75SJijie Shao 	/* After ring buffers have been released,
5140735e75SJijie Shao 	 * do a reset to release hw fifo rx ring buffer
5240735e75SJijie Shao 	 */
5340735e75SJijie Shao 	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
5440735e75SJijie Shao 	if (ret)
5540735e75SJijie Shao 		return ret;
5640735e75SJijie Shao 
5740735e75SJijie Shao 	/* After reset, regs need to be reconfigured */
5840735e75SJijie Shao 	hbg_hw_init(priv);
5940735e75SJijie Shao 	hbg_hw_set_uc_addr(priv, ether_addr_to_u64(priv->netdev->dev_addr));
6040735e75SJijie Shao 	hbg_change_mtu(priv, priv->netdev->mtu);
6140735e75SJijie Shao 
6240735e75SJijie Shao 	return 0;
6340735e75SJijie Shao }
6440735e75SJijie Shao 
65ff4edac6SJijie Shao static int hbg_net_stop(struct net_device *netdev)
66ff4edac6SJijie Shao {
67ff4edac6SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
68ff4edac6SJijie Shao 
69ff4edac6SJijie Shao 	hbg_phy_stop(priv);
70ff4edac6SJijie Shao 	netif_stop_queue(netdev);
71ff4edac6SJijie Shao 	hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
72ff4edac6SJijie Shao 	hbg_all_irq_enable(priv, false);
7340735e75SJijie Shao 	hbg_txrx_uninit(priv);
7440735e75SJijie Shao 	return hbg_hw_txrx_clear(priv);
75ff4edac6SJijie Shao }
76ff4edac6SJijie Shao 
77ff4edac6SJijie Shao static int hbg_net_set_mac_address(struct net_device *netdev, void *addr)
78ff4edac6SJijie Shao {
79ff4edac6SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
80ff4edac6SJijie Shao 	u8 *mac_addr;
81ff4edac6SJijie Shao 
82ff4edac6SJijie Shao 	mac_addr = ((struct sockaddr *)addr)->sa_data;
83ff4edac6SJijie Shao 
84ff4edac6SJijie Shao 	if (!is_valid_ether_addr(mac_addr))
85ff4edac6SJijie Shao 		return -EADDRNOTAVAIL;
86ff4edac6SJijie Shao 
87ff4edac6SJijie Shao 	hbg_hw_set_uc_addr(priv, ether_addr_to_u64(mac_addr));
88ff4edac6SJijie Shao 	dev_addr_set(netdev, mac_addr);
89ff4edac6SJijie Shao 
90ff4edac6SJijie Shao 	return 0;
91ff4edac6SJijie Shao }
92ff4edac6SJijie Shao 
93ff4edac6SJijie Shao static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu)
94ff4edac6SJijie Shao {
95ff4edac6SJijie Shao 	u32 frame_len;
96ff4edac6SJijie Shao 
97ff4edac6SJijie Shao 	frame_len = new_mtu + VLAN_HLEN * priv->dev_specs.vlan_layers +
98ff4edac6SJijie Shao 		    ETH_HLEN + ETH_FCS_LEN;
99ff4edac6SJijie Shao 	hbg_hw_set_mtu(priv, frame_len);
100ff4edac6SJijie Shao }
101ff4edac6SJijie Shao 
102ff4edac6SJijie Shao static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu)
103ff4edac6SJijie Shao {
104ff4edac6SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
105ff4edac6SJijie Shao 
106ff4edac6SJijie Shao 	if (netif_running(netdev))
107ff4edac6SJijie Shao 		return -EBUSY;
108ff4edac6SJijie Shao 
109ff4edac6SJijie Shao 	hbg_change_mtu(priv, new_mtu);
110ff4edac6SJijie Shao 	WRITE_ONCE(netdev->mtu, new_mtu);
111ff4edac6SJijie Shao 
112ff4edac6SJijie Shao 	dev_dbg(&priv->pdev->dev,
113ff4edac6SJijie Shao 		"change mtu from %u to %u\n", netdev->mtu, new_mtu);
114ff4edac6SJijie Shao 
115ff4edac6SJijie Shao 	return 0;
116ff4edac6SJijie Shao }
117ff4edac6SJijie Shao 
11840735e75SJijie Shao static void hbg_net_tx_timeout(struct net_device *netdev, unsigned int txqueue)
11940735e75SJijie Shao {
12040735e75SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
12140735e75SJijie Shao 	struct hbg_ring *ring = &priv->tx_ring;
12240735e75SJijie Shao 	char *buf = ring->tout_log_buf;
12340735e75SJijie Shao 	u32 pos = 0;
12440735e75SJijie Shao 
12540735e75SJijie Shao 	pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
12640735e75SJijie Shao 			 "ring used num: %u, fifo used num: %u\n",
12740735e75SJijie Shao 			 hbg_get_queue_used_num(ring),
12840735e75SJijie Shao 			 hbg_hw_get_fifo_used_num(priv, HBG_DIR_TX));
12940735e75SJijie Shao 	pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
13040735e75SJijie Shao 			 "ntc: %u, ntu: %u, irq enabled: %u\n",
13140735e75SJijie Shao 			 ring->ntc, ring->ntu,
13240735e75SJijie Shao 			 hbg_hw_irq_is_enabled(priv, HBG_INT_MSK_TX_B));
13340735e75SJijie Shao 
13440735e75SJijie Shao 	netdev_info(netdev, "%s", buf);
13540735e75SJijie Shao }
13640735e75SJijie Shao 
137ff4edac6SJijie Shao static const struct net_device_ops hbg_netdev_ops = {
138ff4edac6SJijie Shao 	.ndo_open		= hbg_net_open,
139ff4edac6SJijie Shao 	.ndo_stop		= hbg_net_stop,
14040735e75SJijie Shao 	.ndo_start_xmit		= hbg_net_start_xmit,
141ff4edac6SJijie Shao 	.ndo_validate_addr	= eth_validate_addr,
142ff4edac6SJijie Shao 	.ndo_set_mac_address	= hbg_net_set_mac_address,
143ff4edac6SJijie Shao 	.ndo_change_mtu		= hbg_net_change_mtu,
14440735e75SJijie Shao 	.ndo_tx_timeout		= hbg_net_tx_timeout,
145ff4edac6SJijie Shao };
146ff4edac6SJijie Shao 
147fc1992baSJijie Shao static int hbg_init(struct hbg_priv *priv)
148fc1992baSJijie Shao {
149fc1992baSJijie Shao 	int ret;
150fc1992baSJijie Shao 
151fc1992baSJijie Shao 	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT);
152fc1992baSJijie Shao 	if (ret)
153fc1992baSJijie Shao 		return ret;
154fc1992baSJijie Shao 
155a239b2b1SJijie Shao 	ret = hbg_hw_init(priv);
156a239b2b1SJijie Shao 	if (ret)
157a239b2b1SJijie Shao 		return ret;
158a239b2b1SJijie Shao 
1594d089035SJijie Shao 	ret = hbg_irq_init(priv);
1604d089035SJijie Shao 	if (ret)
1614d089035SJijie Shao 		return ret;
1624d089035SJijie Shao 
163a239b2b1SJijie Shao 	return hbg_mdio_init(priv);
164fc1992baSJijie Shao }
165a95ac4f9SJijie Shao 
166a95ac4f9SJijie Shao static int hbg_pci_init(struct pci_dev *pdev)
167a95ac4f9SJijie Shao {
168a95ac4f9SJijie Shao 	struct net_device *netdev = pci_get_drvdata(pdev);
169a95ac4f9SJijie Shao 	struct hbg_priv *priv = netdev_priv(netdev);
170a95ac4f9SJijie Shao 	struct device *dev = &pdev->dev;
171a95ac4f9SJijie Shao 	int ret;
172a95ac4f9SJijie Shao 
173a95ac4f9SJijie Shao 	ret = pcim_enable_device(pdev);
174a95ac4f9SJijie Shao 	if (ret)
175a95ac4f9SJijie Shao 		return dev_err_probe(dev, ret, "failed to enable PCI device\n");
176a95ac4f9SJijie Shao 
177a95ac4f9SJijie Shao 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
178a95ac4f9SJijie Shao 	if (ret)
179a95ac4f9SJijie Shao 		return dev_err_probe(dev, ret, "failed to set PCI DMA mask\n");
180a95ac4f9SJijie Shao 
181a95ac4f9SJijie Shao 	ret = pcim_iomap_regions(pdev, BIT(0), dev_driver_string(dev));
182a95ac4f9SJijie Shao 	if (ret)
183a95ac4f9SJijie Shao 		return dev_err_probe(dev, ret, "failed to map PCI bar space\n");
184a95ac4f9SJijie Shao 
185a95ac4f9SJijie Shao 	priv->io_base = pcim_iomap_table(pdev)[0];
186a95ac4f9SJijie Shao 	if (!priv->io_base)
187a95ac4f9SJijie Shao 		return dev_err_probe(dev, -ENOMEM, "failed to get io base\n");
188a95ac4f9SJijie Shao 
189a95ac4f9SJijie Shao 	pci_set_master(pdev);
190a95ac4f9SJijie Shao 	return 0;
191a95ac4f9SJijie Shao }
192a95ac4f9SJijie Shao 
193a95ac4f9SJijie Shao static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
194a95ac4f9SJijie Shao {
195a95ac4f9SJijie Shao 	struct device *dev = &pdev->dev;
196a95ac4f9SJijie Shao 	struct net_device *netdev;
197a95ac4f9SJijie Shao 	struct hbg_priv *priv;
198a95ac4f9SJijie Shao 	int ret;
199a95ac4f9SJijie Shao 
200a95ac4f9SJijie Shao 	netdev = devm_alloc_etherdev(dev, sizeof(struct hbg_priv));
201a95ac4f9SJijie Shao 	if (!netdev)
202a95ac4f9SJijie Shao 		return -ENOMEM;
203a95ac4f9SJijie Shao 
204a95ac4f9SJijie Shao 	pci_set_drvdata(pdev, netdev);
205a95ac4f9SJijie Shao 	SET_NETDEV_DEV(netdev, dev);
206a95ac4f9SJijie Shao 
207a95ac4f9SJijie Shao 	priv = netdev_priv(netdev);
208a95ac4f9SJijie Shao 	priv->netdev = netdev;
209a95ac4f9SJijie Shao 	priv->pdev = pdev;
210a95ac4f9SJijie Shao 
211a95ac4f9SJijie Shao 	ret = hbg_pci_init(pdev);
212a95ac4f9SJijie Shao 	if (ret)
213a95ac4f9SJijie Shao 		return ret;
214a95ac4f9SJijie Shao 
215fc1992baSJijie Shao 	ret = hbg_init(priv);
216fc1992baSJijie Shao 	if (ret)
217fc1992baSJijie Shao 		return ret;
218fc1992baSJijie Shao 
219a95ac4f9SJijie Shao 	netdev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
220ff4edac6SJijie Shao 	netdev->max_mtu = priv->dev_specs.max_mtu;
221ff4edac6SJijie Shao 	netdev->min_mtu = priv->dev_specs.min_mtu;
222ff4edac6SJijie Shao 	netdev->netdev_ops = &hbg_netdev_ops;
22340735e75SJijie Shao 	netdev->watchdog_timeo = 5 * HZ;
224ff4edac6SJijie Shao 
225ff4edac6SJijie Shao 	hbg_change_mtu(priv, ETH_DATA_LEN);
226ff4edac6SJijie Shao 	hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr);
227*e8d13548SJijie Shao 	hbg_ethtool_set_ops(netdev);
228a95ac4f9SJijie Shao 
229a95ac4f9SJijie Shao 	ret = devm_register_netdev(dev, netdev);
230a95ac4f9SJijie Shao 	if (ret)
231a95ac4f9SJijie Shao 		return dev_err_probe(dev, ret, "failed to register netdev\n");
232a95ac4f9SJijie Shao 
233a95ac4f9SJijie Shao 	netif_carrier_off(netdev);
234a95ac4f9SJijie Shao 	return 0;
235a95ac4f9SJijie Shao }
236a95ac4f9SJijie Shao 
237a95ac4f9SJijie Shao static const struct pci_device_id hbg_pci_tbl[] = {
238a95ac4f9SJijie Shao 	{PCI_VDEVICE(HUAWEI, 0x3730), 0},
239a95ac4f9SJijie Shao 	{ }
240a95ac4f9SJijie Shao };
241a95ac4f9SJijie Shao MODULE_DEVICE_TABLE(pci, hbg_pci_tbl);
242a95ac4f9SJijie Shao 
243a95ac4f9SJijie Shao static struct pci_driver hbg_driver = {
244a95ac4f9SJijie Shao 	.name		= "hibmcge",
245a95ac4f9SJijie Shao 	.id_table	= hbg_pci_tbl,
246a95ac4f9SJijie Shao 	.probe		= hbg_probe,
247a95ac4f9SJijie Shao };
248a95ac4f9SJijie Shao module_pci_driver(hbg_driver);
249a95ac4f9SJijie Shao 
250a95ac4f9SJijie Shao MODULE_LICENSE("GPL");
251a95ac4f9SJijie Shao MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
252a95ac4f9SJijie Shao MODULE_DESCRIPTION("hibmcge driver");
253a95ac4f9SJijie Shao MODULE_VERSION("1.0");
254