Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'cxgb4-IFLA_VF_MAC'

Hariprasad Shenai says:

====================
cxgb4: Add support for IFLA_VF_MAC

We're struggling to implement the PCI SR-IOV management features for
administering Virtual Functions which represent networking devices using
the current Linux APIs. The problem is that these APIs incorporate all
sorts of assumptions which don't match chelsio networking cards.

For instance, the current APIs assume a 1-to-1 mapping of Network Ports,
Physical Functions and the SR-IOV Virtual Functions of those Physical
Functions. This is not the case with our cards where any Virtual Function
can be hooked up to any Port -- or any number of Ports the current Linux
APIs also assume only 1 Network Interface/Port can be accessed per Virtuali
Function.

Another issue is that these APIs assume that the Administrative Driver is
attached to the Physical Function Associated with a Virtual Function. This
is not the case with our card where all administration is performed by a
Driver which is not attached to any of the Physical Functions which have
SR-IOV PCI Capabilities.

Another consequence of these assumptions is the inability to utilize all
of the cards SR-IOV resources. For instance, our cards have SR-IOV
Capabilities on Physical Functions 0..3 and the administrative Driver
attaches to Physical Function 4. Each of the Physical Functions 0..3 can
support up to 16 Virtual Functions. With the current Linux APIs, a 2-Port
card would only be able to use the Virtual Functions on Physical
Function 0..1 and not allow the Virtual Functions on Physical
Functions 2..3 to be used since there are no Ports 2..3 on a 2-Port card.

Patch 1/2 adds support to create management interface for each PF to control
thier corresponding VF's. Patch 2/2 adds support for ndo_set_vf_mac.

This patch series has been created against net-next tree.

We have included all the maintainers of respective drivers. Kindly review
the change and let us know in case of any review comments.

V5: Fix warning reported by kbuild bot when CONFIG_PCI_IOV isn't defined.

V4: Handle memory allocation failure for adapter->mbox_log in init_one().
Based on review comment by Yuval Mintz <Yuval.Mintz@qlogic.com>

V3: Based on review comment by Yuval Mintz, removed extra parameter pf
added to IFLA_VF API's and created a net_device corresponding to
each PF for controling their VF. Based on review comment by
Yuval Mintz <Yuval.Mintz@qlogic.com>

V2: Fixed check for MAC address in Patch 2/2, based on review comment by
Yuval Mintz <Yuval.Mintz@qlogic.com>
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+253 -24
+3
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
··· 1521 1521 void t4_idma_monitor(struct adapter *adapter, 1522 1522 struct sge_idma_monitor_state *idma, 1523 1523 int hz, int ticks); 1524 + int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, 1525 + unsigned int naddr, u8 *addr); 1526 + 1524 1527 #endif /* __CXGB4_H__ */
+125 -18
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
··· 3078 3078 return ret; 3079 3079 } 3080 3080 3081 + #ifdef CONFIG_PCI_IOV 3082 + static int cxgb_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 3083 + { 3084 + struct port_info *pi = netdev_priv(dev); 3085 + struct adapter *adap = pi->adapter; 3086 + 3087 + /* verify MAC addr is valid */ 3088 + if (!is_valid_ether_addr(mac)) { 3089 + dev_err(pi->adapter->pdev_dev, 3090 + "Invalid Ethernet address %pM for VF %d\n", 3091 + mac, vf); 3092 + return -EINVAL; 3093 + } 3094 + 3095 + dev_info(pi->adapter->pdev_dev, 3096 + "Setting MAC %pM on VF %d\n", mac, vf); 3097 + return t4_set_vf_mac_acl(adap, vf + 1, 1, mac); 3098 + } 3099 + #endif 3100 + 3081 3101 static int cxgb_set_mac_addr(struct net_device *dev, void *p) 3082 3102 { 3083 3103 int ret; ··· 3156 3136 #ifdef CONFIG_NET_RX_BUSY_POLL 3157 3137 .ndo_busy_poll = cxgb_busy_poll, 3158 3138 #endif 3139 + }; 3159 3140 3141 + static const struct net_device_ops cxgb4_mgmt_netdev_ops = { 3142 + #ifdef CONFIG_PCI_IOV 3143 + .ndo_set_vf_mac = cxgb_set_vf_mac, 3144 + #endif 3145 + }; 3146 + 3147 + static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 3148 + { 3149 + struct adapter *adapter = netdev2adap(dev); 3150 + 3151 + strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); 3152 + strlcpy(info->version, cxgb4_driver_version, 3153 + sizeof(info->version)); 3154 + strlcpy(info->bus_info, pci_name(adapter->pdev), 3155 + sizeof(info->bus_info)); 3156 + } 3157 + 3158 + static const struct ethtool_ops cxgb4_mgmt_ethtool_ops = { 3159 + .get_drvinfo = get_drvinfo, 3160 3160 }; 3161 3161 3162 3162 void t4_fatal_err(struct adapter *adap) ··· 4876 4836 #ifdef CONFIG_PCI_IOV 4877 4837 static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) 4878 4838 { 4839 + struct adapter *adap = pci_get_drvdata(pdev); 4879 4840 int err = 0; 4880 4841 int current_vfs = pci_num_vf(pdev); 4881 4842 u32 pcie_fw; 4882 - void __iomem *regs; 4883 4843 4884 - regs = pci_ioremap_bar(pdev, 0); 4885 - if (!regs) { 4886 - dev_err(&pdev->dev, "cannot map device registers\n"); 4887 - return -ENOMEM; 4888 - } 4889 - 4890 - pcie_fw = readl(regs + PCIE_FW_A); 4891 - iounmap(regs); 4844 + pcie_fw = readl(adap->regs + PCIE_FW_A); 4892 4845 /* Check if cxgb4 is the MASTER and fw is initialized */ 4893 4846 if (!(pcie_fw & PCIE_FW_INIT_F) || 4894 4847 !(pcie_fw & PCIE_FW_MASTER_VLD_F) || ··· 4908 4875 */ 4909 4876 if (!num_vfs) { 4910 4877 pci_disable_sriov(pdev); 4878 + if (adap->port[0]->reg_state == NETREG_REGISTERED) 4879 + unregister_netdev(adap->port[0]); 4911 4880 return num_vfs; 4912 4881 } 4913 4882 ··· 4917 4882 err = pci_enable_sriov(pdev, num_vfs); 4918 4883 if (err) 4919 4884 return err; 4885 + 4886 + if (adap->port[0]->reg_state == NETREG_UNINITIALIZED) { 4887 + err = register_netdev(adap->port[0]); 4888 + if (err < 0) 4889 + pr_info("Unable to register VF mgmt netdev\n"); 4890 + } 4920 4891 } 4921 4892 return num_vfs; 4922 4893 } ··· 4934 4893 struct port_info *pi; 4935 4894 bool highdma = false; 4936 4895 struct adapter *adapter = NULL; 4896 + struct net_device *netdev; 4897 + #ifdef CONFIG_PCI_IOV 4898 + char name[IFNAMSIZ]; 4899 + #endif 4937 4900 void __iomem *regs; 4938 4901 u32 whoami, pl_rev; 4939 4902 enum chip_type chip; 4903 + static int adap_idx = 1; 4940 4904 4941 4905 printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); 4942 4906 ··· 4976 4930 func = CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5 ? 4977 4931 SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 4978 4932 if (func != ent->driver_data) { 4933 + #ifndef CONFIG_PCI_IOV 4979 4934 iounmap(regs); 4935 + #endif 4980 4936 pci_disable_device(pdev); 4981 4937 pci_save_state(pdev); /* to restore SR-IOV later */ 4982 4938 goto sriov; ··· 5010 4962 err = -ENOMEM; 5011 4963 goto out_unmap_bar0; 5012 4964 } 4965 + adap_idx++; 5013 4966 5014 4967 adapter->workq = create_singlethread_workqueue("cxgb4"); 5015 4968 if (!adapter->workq) { ··· 5097 5048 T6_STATMODE_V(0))); 5098 5049 5099 5050 for_each_port(adapter, i) { 5100 - struct net_device *netdev; 5101 - 5102 5051 netdev = alloc_etherdev_mq(sizeof(struct port_info), 5103 5052 MAX_ETH_QSETS); 5104 5053 if (!netdev) { ··· 5264 5217 attach_ulds(adapter); 5265 5218 5266 5219 print_adapter_info(adapter); 5220 + return 0; 5267 5221 5268 5222 sriov: 5269 5223 #ifdef CONFIG_PCI_IOV ··· 5278 5230 "instantiated %u virtual functions\n", 5279 5231 num_vf[func]); 5280 5232 } 5281 - #endif 5233 + 5234 + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); 5235 + if (!adapter) { 5236 + err = -ENOMEM; 5237 + goto free_pci_region; 5238 + } 5239 + 5240 + snprintf(name, IFNAMSIZ, "mgmtpf%d%d", adap_idx, func); 5241 + netdev = alloc_netdev(0, name, NET_NAME_UNKNOWN, ether_setup); 5242 + if (!netdev) { 5243 + err = -ENOMEM; 5244 + goto free_adapter; 5245 + } 5246 + 5247 + adapter->pdev = pdev; 5248 + adapter->pdev_dev = &pdev->dev; 5249 + adapter->name = pci_name(pdev); 5250 + adapter->mbox = func; 5251 + adapter->pf = func; 5252 + adapter->regs = regs; 5253 + adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) + 5254 + (sizeof(struct mbox_cmd) * 5255 + T4_OS_LOG_MBOX_CMDS), 5256 + GFP_KERNEL); 5257 + if (!adapter->mbox_log) { 5258 + err = -ENOMEM; 5259 + goto free_netdevice; 5260 + } 5261 + pi = netdev_priv(netdev); 5262 + pi->adapter = adapter; 5263 + SET_NETDEV_DEV(netdev, &pdev->dev); 5264 + pci_set_drvdata(pdev, adapter); 5265 + 5266 + adapter->port[0] = netdev; 5267 + netdev->netdev_ops = &cxgb4_mgmt_netdev_ops; 5268 + netdev->ethtool_ops = &cxgb4_mgmt_ethtool_ops; 5269 + 5282 5270 return 0; 5271 + 5272 + free_netdevice: 5273 + free_netdev(adapter->port[0]); 5274 + free_adapter: 5275 + kfree(adapter); 5276 + free_pci_region: 5277 + iounmap(regs); 5278 + pci_disable_sriov(pdev); 5279 + pci_release_regions(pdev); 5280 + return err; 5281 + #else 5282 + return 0; 5283 + #endif 5283 5284 5284 5285 out_free_dev: 5285 5286 free_some_resources(adapter); ··· 5355 5258 { 5356 5259 struct adapter *adapter = pci_get_drvdata(pdev); 5357 5260 5358 - #ifdef CONFIG_PCI_IOV 5359 - pci_disable_sriov(pdev); 5261 + if (!adapter) { 5262 + pci_release_regions(pdev); 5263 + return; 5264 + } 5360 5265 5361 - #endif 5362 - 5363 - if (adapter) { 5266 + if (adapter->pf == 4) { 5364 5267 int i; 5365 5268 5366 5269 /* Tear down per-adapter Work Queue first since it can contain ··· 5409 5312 kfree(adapter->mbox_log); 5410 5313 synchronize_rcu(); 5411 5314 kfree(adapter); 5412 - } else 5315 + } 5316 + #ifdef CONFIG_PCI_IOV 5317 + else { 5318 + if (adapter->port[0]->reg_state == NETREG_REGISTERED) 5319 + unregister_netdev(adapter->port[0]); 5320 + free_netdev(adapter->port[0]); 5321 + iounmap(adapter->regs); 5322 + kfree(adapter); 5323 + pci_disable_sriov(pdev); 5413 5324 pci_release_regions(pdev); 5325 + } 5326 + #endif 5414 5327 } 5415 5328 5416 5329 static struct pci_driver cxgb4_driver = {
+41
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
··· 8264 8264 t4_sge_decode_idma_state(adapter, idma->idma_state[i]); 8265 8265 } 8266 8266 } 8267 + 8268 + /** 8269 + * t4_set_vf_mac - Set MAC address for the specified VF 8270 + * @adapter: The adapter 8271 + * @vf: one of the VFs instantiated by the specified PF 8272 + * @naddr: the number of MAC addresses 8273 + * @addr: the MAC address(es) to be set to the specified VF 8274 + */ 8275 + int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, 8276 + unsigned int naddr, u8 *addr) 8277 + { 8278 + struct fw_acl_mac_cmd cmd; 8279 + 8280 + memset(&cmd, 0, sizeof(cmd)); 8281 + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_MAC_CMD) | 8282 + FW_CMD_REQUEST_F | 8283 + FW_CMD_WRITE_F | 8284 + FW_ACL_MAC_CMD_PFN_V(adapter->pf) | 8285 + FW_ACL_MAC_CMD_VFN_V(vf)); 8286 + 8287 + /* Note: Do not enable the ACL */ 8288 + cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); 8289 + cmd.nmac = naddr; 8290 + 8291 + switch (adapter->pf) { 8292 + case 3: 8293 + memcpy(cmd.macaddr3, addr, sizeof(cmd.macaddr3)); 8294 + break; 8295 + case 2: 8296 + memcpy(cmd.macaddr2, addr, sizeof(cmd.macaddr2)); 8297 + break; 8298 + case 1: 8299 + memcpy(cmd.macaddr1, addr, sizeof(cmd.macaddr1)); 8300 + break; 8301 + case 0: 8302 + memcpy(cmd.macaddr0, addr, sizeof(cmd.macaddr0)); 8303 + break; 8304 + } 8305 + 8306 + return t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &cmd); 8307 + }
+24
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
··· 2777 2777 struct adapter *adapter; 2778 2778 struct port_info *pi; 2779 2779 struct net_device *netdev; 2780 + unsigned int pf; 2780 2781 2781 2782 /* 2782 2783 * Print our driver banner the first time we're called to initialize a ··· 2904 2903 * Allocate our "adapter ports" and stitch everything together. 2905 2904 */ 2906 2905 pmask = adapter->params.vfres.pmask; 2906 + pf = t4vf_get_pf_from_vf(adapter); 2907 2907 for_each_port(adapter, pidx) { 2908 2908 int port_id, viid; 2909 + u8 mac[ETH_ALEN]; 2910 + unsigned int naddr = 1; 2909 2911 2910 2912 /* 2911 2913 * We simplistically allocate our virtual interfaces ··· 2978 2974 dev_err(&pdev->dev, "cannot initialize port %d\n", 2979 2975 pidx); 2980 2976 goto err_free_dev; 2977 + } 2978 + 2979 + err = t4vf_get_vf_mac_acl(adapter, pf, &naddr, mac); 2980 + if (err) { 2981 + dev_err(&pdev->dev, 2982 + "unable to determine MAC ACL address, " 2983 + "continuing anyway.. (status %d)\n", err); 2984 + } else if (naddr && adapter->params.vfres.nvi == 1) { 2985 + struct sockaddr addr; 2986 + 2987 + ether_addr_copy(addr.sa_data, mac); 2988 + err = cxgb4vf_set_mac_addr(netdev, &addr); 2989 + if (err) { 2990 + dev_err(&pdev->dev, 2991 + "unable to set MAC address %pM\n", 2992 + mac); 2993 + goto err_free_dev; 2994 + } 2995 + dev_info(&pdev->dev, 2996 + "Using assigned MAC ACL: %pM\n", mac); 2981 2997 } 2982 2998 } 2983 2999
+3
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
··· 347 347 u64 *pbar2_qoffset, 348 348 unsigned int *pbar2_qid); 349 349 350 + unsigned int t4vf_get_pf_from_vf(struct adapter *); 350 351 int t4vf_get_sge_params(struct adapter *); 351 352 int t4vf_get_vpd_params(struct adapter *); 352 353 int t4vf_get_dev_params(struct adapter *); ··· 382 381 383 382 int t4vf_handle_fw_rpl(struct adapter *, const __be64 *); 384 383 int t4vf_prep_adapter(struct adapter *); 384 + int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int pf, 385 + unsigned int *naddr, u8 *addr); 385 386 386 387 #endif /* __T4VF_COMMON_H__ */
+57 -6
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
··· 639 639 return 0; 640 640 } 641 641 642 + unsigned int t4vf_get_pf_from_vf(struct adapter *adapter) 643 + { 644 + u32 whoami; 645 + 646 + whoami = t4_read_reg(adapter, T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); 647 + return (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? 648 + SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami)); 649 + } 650 + 642 651 /** 643 652 * t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters 644 653 * @adapter: the adapter ··· 725 716 * read. 726 717 */ 727 718 if (!is_t4(adapter->params.chip)) { 728 - u32 whoami; 729 719 unsigned int pf, s_hps, s_qpp; 730 720 731 721 params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | ··· 748 740 * register we just read. Do it once here so other code in 749 741 * the driver can just use it. 750 742 */ 751 - whoami = t4_read_reg(adapter, 752 - T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); 753 - pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? 754 - SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 755 - 743 + pf = t4vf_get_pf_from_vf(adapter); 756 744 s_hps = (HOSTPAGESIZEPF0_S + 757 745 (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf); 758 746 sge_params->sge_vf_hps = ··· 1810 1806 } 1811 1807 1812 1808 return 0; 1809 + } 1810 + 1811 + /** 1812 + * t4vf_get_vf_mac_acl - Get the MAC address to be set to 1813 + * the VI of this VF. 1814 + * @adapter: The adapter 1815 + * @pf: The pf associated with vf 1816 + * @naddr: the number of ACL MAC addresses returned in addr 1817 + * @addr: Placeholder for MAC addresses 1818 + * 1819 + * Find the MAC address to be set to the VF's VI. The requested MAC address 1820 + * is from the host OS via callback in the PF driver. 1821 + */ 1822 + int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int pf, 1823 + unsigned int *naddr, u8 *addr) 1824 + { 1825 + struct fw_acl_mac_cmd cmd; 1826 + int ret; 1827 + 1828 + memset(&cmd, 0, sizeof(cmd)); 1829 + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_MAC_CMD) | 1830 + FW_CMD_REQUEST_F | 1831 + FW_CMD_READ_F); 1832 + cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); 1833 + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &cmd); 1834 + if (ret) 1835 + return ret; 1836 + 1837 + if (cmd.nmac < *naddr) 1838 + *naddr = cmd.nmac; 1839 + 1840 + switch (pf) { 1841 + case 3: 1842 + memcpy(addr, cmd.macaddr3, sizeof(cmd.macaddr3)); 1843 + break; 1844 + case 2: 1845 + memcpy(addr, cmd.macaddr2, sizeof(cmd.macaddr2)); 1846 + break; 1847 + case 1: 1848 + memcpy(addr, cmd.macaddr1, sizeof(cmd.macaddr1)); 1849 + break; 1850 + case 0: 1851 + memcpy(addr, cmd.macaddr0, sizeof(cmd.macaddr0)); 1852 + break; 1853 + } 1854 + 1855 + return ret; 1813 1856 }