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