1d4fd0404SClaudiu Manoil // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2d4fd0404SClaudiu Manoil /* Copyright 2017-2019 NXP */ 3d4fd0404SClaudiu Manoil 4d4fd0404SClaudiu Manoil #include <linux/module.h> 5d4fd0404SClaudiu Manoil #include "enetc.h" 6d4fd0404SClaudiu Manoil 7d4fd0404SClaudiu Manoil #define ENETC_DRV_NAME_STR "ENETC VF driver" 8d4fd0404SClaudiu Manoil 9beb74ac8SClaudiu Manoil /* Messaging */ 10beb74ac8SClaudiu Manoil static void enetc_msg_vsi_write_msg(struct enetc_hw *hw, 11beb74ac8SClaudiu Manoil struct enetc_msg_swbd *msg) 12beb74ac8SClaudiu Manoil { 13beb74ac8SClaudiu Manoil u32 val; 14beb74ac8SClaudiu Manoil 15beb74ac8SClaudiu Manoil val = enetc_vsi_set_msize(msg->size) | lower_32_bits(msg->dma); 16beb74ac8SClaudiu Manoil enetc_wr(hw, ENETC_VSIMSGSNDAR1, upper_32_bits(msg->dma)); 17beb74ac8SClaudiu Manoil enetc_wr(hw, ENETC_VSIMSGSNDAR0, val); 18beb74ac8SClaudiu Manoil } 19beb74ac8SClaudiu Manoil 20beb74ac8SClaudiu Manoil static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg) 21beb74ac8SClaudiu Manoil { 22beb74ac8SClaudiu Manoil int timeout = 100; 23beb74ac8SClaudiu Manoil u32 vsimsgsr; 24beb74ac8SClaudiu Manoil 25beb74ac8SClaudiu Manoil enetc_msg_vsi_write_msg(&si->hw, msg); 26beb74ac8SClaudiu Manoil 27beb74ac8SClaudiu Manoil do { 28beb74ac8SClaudiu Manoil vsimsgsr = enetc_rd(&si->hw, ENETC_VSIMSGSR); 29beb74ac8SClaudiu Manoil if (!(vsimsgsr & ENETC_VSIMSGSR_MB)) 30beb74ac8SClaudiu Manoil break; 31beb74ac8SClaudiu Manoil 32beb74ac8SClaudiu Manoil usleep_range(1000, 2000); 33beb74ac8SClaudiu Manoil } while (--timeout); 34beb74ac8SClaudiu Manoil 35beb74ac8SClaudiu Manoil if (!timeout) 36beb74ac8SClaudiu Manoil return -ETIMEDOUT; 37beb74ac8SClaudiu Manoil 38beb74ac8SClaudiu Manoil /* check for message delivery error */ 39beb74ac8SClaudiu Manoil if (vsimsgsr & ENETC_VSIMSGSR_MS) { 40beb74ac8SClaudiu Manoil dev_err(&si->pdev->dev, "VSI command execute error: %d\n", 41beb74ac8SClaudiu Manoil ENETC_SIMSGSR_GET_MC(vsimsgsr)); 42beb74ac8SClaudiu Manoil return -EIO; 43beb74ac8SClaudiu Manoil } 44beb74ac8SClaudiu Manoil 45beb74ac8SClaudiu Manoil return 0; 46beb74ac8SClaudiu Manoil } 47beb74ac8SClaudiu Manoil 48beb74ac8SClaudiu Manoil static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv, 49beb74ac8SClaudiu Manoil struct sockaddr *saddr) 50beb74ac8SClaudiu Manoil { 51beb74ac8SClaudiu Manoil struct enetc_msg_cmd_set_primary_mac *cmd; 52beb74ac8SClaudiu Manoil struct enetc_msg_swbd msg; 53beb74ac8SClaudiu Manoil int err; 54beb74ac8SClaudiu Manoil 55beb74ac8SClaudiu Manoil msg.size = ALIGN(sizeof(struct enetc_msg_cmd_set_primary_mac), 64); 56beb74ac8SClaudiu Manoil msg.vaddr = dma_alloc_coherent(priv->dev, msg.size, &msg.dma, 57beb74ac8SClaudiu Manoil GFP_KERNEL); 58beb74ac8SClaudiu Manoil if (!msg.vaddr) { 59beb74ac8SClaudiu Manoil dev_err(priv->dev, "Failed to alloc Tx msg (size: %d)\n", 60beb74ac8SClaudiu Manoil msg.size); 61beb74ac8SClaudiu Manoil return -ENOMEM; 62beb74ac8SClaudiu Manoil } 63beb74ac8SClaudiu Manoil 64beb74ac8SClaudiu Manoil cmd = (struct enetc_msg_cmd_set_primary_mac *)msg.vaddr; 65beb74ac8SClaudiu Manoil cmd->header.type = ENETC_MSG_CMD_MNG_MAC; 66beb74ac8SClaudiu Manoil cmd->header.id = ENETC_MSG_CMD_MNG_ADD; 67beb74ac8SClaudiu Manoil memcpy(&cmd->mac, saddr, sizeof(struct sockaddr)); 68beb74ac8SClaudiu Manoil 69beb74ac8SClaudiu Manoil /* send the command and wait */ 70beb74ac8SClaudiu Manoil err = enetc_msg_vsi_send(priv->si, &msg); 71beb74ac8SClaudiu Manoil 72beb74ac8SClaudiu Manoil dma_free_coherent(priv->dev, msg.size, msg.vaddr, msg.dma); 73beb74ac8SClaudiu Manoil 74beb74ac8SClaudiu Manoil return err; 75beb74ac8SClaudiu Manoil } 76beb74ac8SClaudiu Manoil 77beb74ac8SClaudiu Manoil static int enetc_vf_set_mac_addr(struct net_device *ndev, void *addr) 78beb74ac8SClaudiu Manoil { 79beb74ac8SClaudiu Manoil struct enetc_ndev_priv *priv = netdev_priv(ndev); 80beb74ac8SClaudiu Manoil struct sockaddr *saddr = addr; 81beb74ac8SClaudiu Manoil 82beb74ac8SClaudiu Manoil if (!is_valid_ether_addr(saddr->sa_data)) 83beb74ac8SClaudiu Manoil return -EADDRNOTAVAIL; 84beb74ac8SClaudiu Manoil 85d4b717ddSQinglang Miao return enetc_msg_vsi_set_primary_mac_addr(priv, saddr); 86beb74ac8SClaudiu Manoil } 87beb74ac8SClaudiu Manoil 88d382563fSClaudiu Manoil static int enetc_vf_set_features(struct net_device *ndev, 89d382563fSClaudiu Manoil netdev_features_t features) 90d382563fSClaudiu Manoil { 91d382563fSClaudiu Manoil return enetc_set_features(ndev, features); 92d382563fSClaudiu Manoil } 93d382563fSClaudiu Manoil 94d4fd0404SClaudiu Manoil /* Probing/ Init */ 95d4fd0404SClaudiu Manoil static const struct net_device_ops enetc_ndev_ops = { 96d4fd0404SClaudiu Manoil .ndo_open = enetc_open, 97d4fd0404SClaudiu Manoil .ndo_stop = enetc_close, 98d4fd0404SClaudiu Manoil .ndo_start_xmit = enetc_xmit, 99d4fd0404SClaudiu Manoil .ndo_get_stats = enetc_get_stats, 100beb74ac8SClaudiu Manoil .ndo_set_mac_address = enetc_vf_set_mac_addr, 101d382563fSClaudiu Manoil .ndo_set_features = enetc_vf_set_features, 102d3982312SY.b. Lu .ndo_do_ioctl = enetc_ioctl, 103cbe9e835SCamelia Groza .ndo_setup_tc = enetc_setup_tc, 104d4fd0404SClaudiu Manoil }; 105d4fd0404SClaudiu Manoil 106d4fd0404SClaudiu Manoil static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev, 107d4fd0404SClaudiu Manoil const struct net_device_ops *ndev_ops) 108d4fd0404SClaudiu Manoil { 109d4fd0404SClaudiu Manoil struct enetc_ndev_priv *priv = netdev_priv(ndev); 110d4fd0404SClaudiu Manoil 111d4fd0404SClaudiu Manoil SET_NETDEV_DEV(ndev, &si->pdev->dev); 112d4fd0404SClaudiu Manoil priv->ndev = ndev; 113d4fd0404SClaudiu Manoil priv->si = si; 114d4fd0404SClaudiu Manoil priv->dev = &si->pdev->dev; 115d4fd0404SClaudiu Manoil si->ndev = ndev; 116d4fd0404SClaudiu Manoil 117d4fd0404SClaudiu Manoil priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1; 118d4fd0404SClaudiu Manoil ndev->netdev_ops = ndev_ops; 119d4fd0404SClaudiu Manoil enetc_set_ethtool_ops(ndev); 120d4fd0404SClaudiu Manoil ndev->watchdog_timeo = 5 * HZ; 121d4fd0404SClaudiu Manoil ndev->max_mtu = ENETC_MAX_MTU; 122d4fd0404SClaudiu Manoil 12382728b91SClaudiu Manoil ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | 124d4fd0404SClaudiu Manoil NETIF_F_HW_VLAN_CTAG_TX | 125d4fd0404SClaudiu Manoil NETIF_F_HW_VLAN_CTAG_RX; 12682728b91SClaudiu Manoil ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM | 127d4fd0404SClaudiu Manoil NETIF_F_HW_VLAN_CTAG_TX | 128d4fd0404SClaudiu Manoil NETIF_F_HW_VLAN_CTAG_RX; 129d4fd0404SClaudiu Manoil 130d382563fSClaudiu Manoil if (si->num_rss) 131d382563fSClaudiu Manoil ndev->hw_features |= NETIF_F_RXHASH; 132d382563fSClaudiu Manoil 133d4fd0404SClaudiu Manoil /* pick up primary MAC address from SI */ 134d4fd0404SClaudiu Manoil enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr); 135d4fd0404SClaudiu Manoil } 136d4fd0404SClaudiu Manoil 137d4fd0404SClaudiu Manoil static int enetc_vf_probe(struct pci_dev *pdev, 138d4fd0404SClaudiu Manoil const struct pci_device_id *ent) 139d4fd0404SClaudiu Manoil { 140d4fd0404SClaudiu Manoil struct enetc_ndev_priv *priv; 141d4fd0404SClaudiu Manoil struct net_device *ndev; 142d4fd0404SClaudiu Manoil struct enetc_si *si; 143d4fd0404SClaudiu Manoil int err; 144d4fd0404SClaudiu Manoil 145d4fd0404SClaudiu Manoil err = enetc_pci_probe(pdev, KBUILD_MODNAME, 0); 146d4fd0404SClaudiu Manoil if (err) { 147d4fd0404SClaudiu Manoil dev_err(&pdev->dev, "PCI probing failed\n"); 148d4fd0404SClaudiu Manoil return err; 149d4fd0404SClaudiu Manoil } 150d4fd0404SClaudiu Manoil 151d4fd0404SClaudiu Manoil si = pci_get_drvdata(pdev); 152d4fd0404SClaudiu Manoil 153d4fd0404SClaudiu Manoil enetc_get_si_caps(si); 154d4fd0404SClaudiu Manoil 155d4fd0404SClaudiu Manoil ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS); 156d4fd0404SClaudiu Manoil if (!ndev) { 157d4fd0404SClaudiu Manoil err = -ENOMEM; 158d4fd0404SClaudiu Manoil dev_err(&pdev->dev, "netdev creation failed\n"); 159d4fd0404SClaudiu Manoil goto err_alloc_netdev; 160d4fd0404SClaudiu Manoil } 161d4fd0404SClaudiu Manoil 162d4fd0404SClaudiu Manoil enetc_vf_netdev_setup(si, ndev, &enetc_ndev_ops); 163d4fd0404SClaudiu Manoil 164d4fd0404SClaudiu Manoil priv = netdev_priv(ndev); 165d4fd0404SClaudiu Manoil 166d4fd0404SClaudiu Manoil enetc_init_si_rings_params(priv); 167d4fd0404SClaudiu Manoil 168d4fd0404SClaudiu Manoil err = enetc_alloc_si_resources(priv); 169d4fd0404SClaudiu Manoil if (err) { 170d4fd0404SClaudiu Manoil dev_err(&pdev->dev, "SI resource alloc failed\n"); 171d4fd0404SClaudiu Manoil goto err_alloc_si_res; 172d4fd0404SClaudiu Manoil } 173d4fd0404SClaudiu Manoil 174*c646d10dSVladimir Oltean err = enetc_configure_si(priv); 175*c646d10dSVladimir Oltean if (err) { 176*c646d10dSVladimir Oltean dev_err(&pdev->dev, "Failed to configure SI\n"); 177*c646d10dSVladimir Oltean goto err_config_si; 178*c646d10dSVladimir Oltean } 179*c646d10dSVladimir Oltean 180d4fd0404SClaudiu Manoil err = enetc_alloc_msix(priv); 181d4fd0404SClaudiu Manoil if (err) { 182d4fd0404SClaudiu Manoil dev_err(&pdev->dev, "MSIX alloc failed\n"); 183d4fd0404SClaudiu Manoil goto err_alloc_msix; 184d4fd0404SClaudiu Manoil } 185d4fd0404SClaudiu Manoil 186d4fd0404SClaudiu Manoil err = register_netdev(ndev); 187d4fd0404SClaudiu Manoil if (err) 188d4fd0404SClaudiu Manoil goto err_reg_netdev; 189d4fd0404SClaudiu Manoil 190d4fd0404SClaudiu Manoil netif_carrier_off(ndev); 191d4fd0404SClaudiu Manoil 192d4fd0404SClaudiu Manoil return 0; 193d4fd0404SClaudiu Manoil 194d4fd0404SClaudiu Manoil err_reg_netdev: 195d4fd0404SClaudiu Manoil enetc_free_msix(priv); 196*c646d10dSVladimir Oltean err_config_si: 197d4fd0404SClaudiu Manoil err_alloc_msix: 198d4fd0404SClaudiu Manoil enetc_free_si_resources(priv); 199d4fd0404SClaudiu Manoil err_alloc_si_res: 200d4fd0404SClaudiu Manoil si->ndev = NULL; 201d4fd0404SClaudiu Manoil free_netdev(ndev); 202d4fd0404SClaudiu Manoil err_alloc_netdev: 203d4fd0404SClaudiu Manoil enetc_pci_remove(pdev); 204d4fd0404SClaudiu Manoil 205d4fd0404SClaudiu Manoil return err; 206d4fd0404SClaudiu Manoil } 207d4fd0404SClaudiu Manoil 208d4fd0404SClaudiu Manoil static void enetc_vf_remove(struct pci_dev *pdev) 209d4fd0404SClaudiu Manoil { 210d4fd0404SClaudiu Manoil struct enetc_si *si = pci_get_drvdata(pdev); 211d4fd0404SClaudiu Manoil struct enetc_ndev_priv *priv; 212d4fd0404SClaudiu Manoil 213d4fd0404SClaudiu Manoil priv = netdev_priv(si->ndev); 214d4fd0404SClaudiu Manoil unregister_netdev(si->ndev); 215d4fd0404SClaudiu Manoil 216d4fd0404SClaudiu Manoil enetc_free_msix(priv); 217d4fd0404SClaudiu Manoil 218d4fd0404SClaudiu Manoil enetc_free_si_resources(priv); 219d4fd0404SClaudiu Manoil 220d4fd0404SClaudiu Manoil free_netdev(si->ndev); 221d4fd0404SClaudiu Manoil 222d4fd0404SClaudiu Manoil enetc_pci_remove(pdev); 223d4fd0404SClaudiu Manoil } 224d4fd0404SClaudiu Manoil 225d4fd0404SClaudiu Manoil static const struct pci_device_id enetc_vf_id_table[] = { 226d4fd0404SClaudiu Manoil { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_VF) }, 227d4fd0404SClaudiu Manoil { 0, } /* End of table. */ 228d4fd0404SClaudiu Manoil }; 229d4fd0404SClaudiu Manoil MODULE_DEVICE_TABLE(pci, enetc_vf_id_table); 230d4fd0404SClaudiu Manoil 231d4fd0404SClaudiu Manoil static struct pci_driver enetc_vf_driver = { 232d4fd0404SClaudiu Manoil .name = KBUILD_MODNAME, 233d4fd0404SClaudiu Manoil .id_table = enetc_vf_id_table, 234d4fd0404SClaudiu Manoil .probe = enetc_vf_probe, 235d4fd0404SClaudiu Manoil .remove = enetc_vf_remove, 236d4fd0404SClaudiu Manoil }; 237d4fd0404SClaudiu Manoil module_pci_driver(enetc_vf_driver); 238d4fd0404SClaudiu Manoil 239d4fd0404SClaudiu Manoil MODULE_DESCRIPTION(ENETC_DRV_NAME_STR); 240d4fd0404SClaudiu Manoil MODULE_LICENSE("Dual BSD/GPL"); 241