diff options
author | David S. Miller <davem@davemloft.net> | 2015-07-08 19:07:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-08 19:07:34 -0400 |
commit | 4df48e8c0e9f210f54bcf975aa6c39cf67672781 (patch) | |
tree | 16dff7897a89df2fd934d73dc960057603aa406e | |
parent | b5a983f3141239b5b0b4a4e66efa31f8a26354b8 (diff) | |
parent | 535a61777f44eebcb71f2a6866f95b17ee0f13c7 (diff) |
Merge branch 'sfc-set-mac'
Shradha Shah says:
====================
sfc: compat for lack of VADAPTOR_SET_MAC in adaptor_firmware <= 4.1.1.1023
This patch series resolves an incompatibility with legacy
firmware due to the lack of MC_CMD_VADAPTOR_SET_MAC in
adaptor_firmware <= 4.1.1.1023
Unless this patch series is applied there will be a compatibility
issue between the driver and Solarflare adapters running older
firmware.
Tested with and without CONFIG_SFC_SRIOV
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 172 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef10_sriov.c | 42 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef10_sriov.h | 6 |
3 files changed, 151 insertions, 69 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 847643455468..605cc8948594 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c | |||
@@ -101,6 +101,11 @@ static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx) | |||
101 | return resource_size(&efx->pci_dev->resource[bar]); | 101 | return resource_size(&efx->pci_dev->resource[bar]); |
102 | } | 102 | } |
103 | 103 | ||
104 | static bool efx_ef10_is_vf(struct efx_nic *efx) | ||
105 | { | ||
106 | return efx->type->is_vf; | ||
107 | } | ||
108 | |||
104 | static int efx_ef10_get_pf_index(struct efx_nic *efx) | 109 | static int efx_ef10_get_pf_index(struct efx_nic *efx) |
105 | { | 110 | { |
106 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN); | 111 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN); |
@@ -677,6 +682,48 @@ static int efx_ef10_probe_pf(struct efx_nic *efx) | |||
677 | return efx_ef10_probe(efx); | 682 | return efx_ef10_probe(efx); |
678 | } | 683 | } |
679 | 684 | ||
685 | int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id) | ||
686 | { | ||
687 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN); | ||
688 | |||
689 | MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); | ||
690 | return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf), | ||
691 | NULL, 0, NULL); | ||
692 | } | ||
693 | |||
694 | int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id) | ||
695 | { | ||
696 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN); | ||
697 | |||
698 | MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); | ||
699 | return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf), | ||
700 | NULL, 0, NULL); | ||
701 | } | ||
702 | |||
703 | int efx_ef10_vport_add_mac(struct efx_nic *efx, | ||
704 | unsigned int port_id, u8 *mac) | ||
705 | { | ||
706 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN); | ||
707 | |||
708 | MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id); | ||
709 | ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac); | ||
710 | |||
711 | return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf, | ||
712 | sizeof(inbuf), NULL, 0, NULL); | ||
713 | } | ||
714 | |||
715 | int efx_ef10_vport_del_mac(struct efx_nic *efx, | ||
716 | unsigned int port_id, u8 *mac) | ||
717 | { | ||
718 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); | ||
719 | |||
720 | MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); | ||
721 | ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); | ||
722 | |||
723 | return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, | ||
724 | sizeof(inbuf), NULL, 0, NULL); | ||
725 | } | ||
726 | |||
680 | #ifdef CONFIG_SFC_SRIOV | 727 | #ifdef CONFIG_SFC_SRIOV |
681 | static int efx_ef10_probe_vf(struct efx_nic *efx) | 728 | static int efx_ef10_probe_vf(struct efx_nic *efx) |
682 | { | 729 | { |
@@ -3804,6 +3851,72 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) | |||
3804 | WARN_ON(remove_failed); | 3851 | WARN_ON(remove_failed); |
3805 | } | 3852 | } |
3806 | 3853 | ||
3854 | static int efx_ef10_vport_set_mac_address(struct efx_nic *efx) | ||
3855 | { | ||
3856 | struct efx_ef10_nic_data *nic_data = efx->nic_data; | ||
3857 | u8 mac_old[ETH_ALEN]; | ||
3858 | int rc, rc2; | ||
3859 | |||
3860 | /* Only reconfigure a PF-created vport */ | ||
3861 | if (is_zero_ether_addr(nic_data->vport_mac)) | ||
3862 | return 0; | ||
3863 | |||
3864 | efx_device_detach_sync(efx); | ||
3865 | efx_net_stop(efx->net_dev); | ||
3866 | down_write(&efx->filter_sem); | ||
3867 | efx_ef10_filter_table_remove(efx); | ||
3868 | up_write(&efx->filter_sem); | ||
3869 | |||
3870 | rc = efx_ef10_vadaptor_free(efx, nic_data->vport_id); | ||
3871 | if (rc) | ||
3872 | goto restore_filters; | ||
3873 | |||
3874 | ether_addr_copy(mac_old, nic_data->vport_mac); | ||
3875 | rc = efx_ef10_vport_del_mac(efx, nic_data->vport_id, | ||
3876 | nic_data->vport_mac); | ||
3877 | if (rc) | ||
3878 | goto restore_vadaptor; | ||
3879 | |||
3880 | rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, | ||
3881 | efx->net_dev->dev_addr); | ||
3882 | if (!rc) { | ||
3883 | ether_addr_copy(nic_data->vport_mac, efx->net_dev->dev_addr); | ||
3884 | } else { | ||
3885 | rc2 = efx_ef10_vport_add_mac(efx, nic_data->vport_id, mac_old); | ||
3886 | if (rc2) { | ||
3887 | /* Failed to add original MAC, so clear vport_mac */ | ||
3888 | eth_zero_addr(nic_data->vport_mac); | ||
3889 | goto reset_nic; | ||
3890 | } | ||
3891 | } | ||
3892 | |||
3893 | restore_vadaptor: | ||
3894 | rc2 = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); | ||
3895 | if (rc2) | ||
3896 | goto reset_nic; | ||
3897 | restore_filters: | ||
3898 | down_write(&efx->filter_sem); | ||
3899 | rc2 = efx_ef10_filter_table_probe(efx); | ||
3900 | up_write(&efx->filter_sem); | ||
3901 | if (rc2) | ||
3902 | goto reset_nic; | ||
3903 | |||
3904 | rc2 = efx_net_open(efx->net_dev); | ||
3905 | if (rc2) | ||
3906 | goto reset_nic; | ||
3907 | |||
3908 | netif_device_attach(efx->net_dev); | ||
3909 | |||
3910 | return rc; | ||
3911 | |||
3912 | reset_nic: | ||
3913 | netif_err(efx, drv, efx->net_dev, | ||
3914 | "Failed to restore when changing MAC address - scheduling reset\n"); | ||
3915 | efx_schedule_reset(efx, RESET_TYPE_DATAPATH); | ||
3916 | |||
3917 | return rc ? rc : rc2; | ||
3918 | } | ||
3919 | |||
3807 | static int efx_ef10_set_mac_address(struct efx_nic *efx) | 3920 | static int efx_ef10_set_mac_address(struct efx_nic *efx) |
3808 | { | 3921 | { |
3809 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); | 3922 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); |
@@ -3820,8 +3933,8 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) | |||
3820 | efx->net_dev->dev_addr); | 3933 | efx->net_dev->dev_addr); |
3821 | MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, | 3934 | MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, |
3822 | nic_data->vport_id); | 3935 | nic_data->vport_id); |
3823 | rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf, | 3936 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf, |
3824 | sizeof(inbuf), NULL, 0, NULL); | 3937 | sizeof(inbuf), NULL, 0, NULL); |
3825 | 3938 | ||
3826 | efx_ef10_filter_table_probe(efx); | 3939 | efx_ef10_filter_table_probe(efx); |
3827 | up_write(&efx->filter_sem); | 3940 | up_write(&efx->filter_sem); |
@@ -3829,38 +3942,27 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) | |||
3829 | efx_net_open(efx->net_dev); | 3942 | efx_net_open(efx->net_dev); |
3830 | netif_device_attach(efx->net_dev); | 3943 | netif_device_attach(efx->net_dev); |
3831 | 3944 | ||
3832 | #if !defined(CONFIG_SFC_SRIOV) | 3945 | #ifdef CONFIG_SFC_SRIOV |
3833 | if (rc == -EPERM) | 3946 | if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) { |
3834 | netif_err(efx, drv, efx->net_dev, | ||
3835 | "Cannot change MAC address; use sfboot to enable mac-spoofing" | ||
3836 | " on this interface\n"); | ||
3837 | #else | ||
3838 | if (rc == -EPERM) { | ||
3839 | struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; | 3947 | struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; |
3840 | 3948 | ||
3841 | /* Switch to PF and change MAC address on vport */ | 3949 | if (rc == -EPERM) { |
3842 | if (efx->pci_dev->is_virtfn && pci_dev_pf) { | 3950 | struct efx_nic *efx_pf; |
3843 | struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); | ||
3844 | 3951 | ||
3845 | if (!efx_ef10_sriov_set_vf_mac(efx_pf, | 3952 | /* Switch to PF and change MAC address on vport */ |
3846 | nic_data->vf_index, | 3953 | efx_pf = pci_get_drvdata(pci_dev_pf); |
3847 | efx->net_dev->dev_addr)) | ||
3848 | return 0; | ||
3849 | } | ||
3850 | netif_err(efx, drv, efx->net_dev, | ||
3851 | "Cannot change MAC address; use sfboot to enable mac-spoofing" | ||
3852 | " on this interface\n"); | ||
3853 | } else if (efx->pci_dev->is_virtfn) { | ||
3854 | /* Successfully changed by VF (with MAC spoofing), so update the | ||
3855 | * parent PF if possible. | ||
3856 | */ | ||
3857 | struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; | ||
3858 | 3954 | ||
3859 | if (pci_dev_pf) { | 3955 | rc = efx_ef10_sriov_set_vf_mac(efx_pf, |
3956 | nic_data->vf_index, | ||
3957 | efx->net_dev->dev_addr); | ||
3958 | } else if (!rc) { | ||
3860 | struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); | 3959 | struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); |
3861 | struct efx_ef10_nic_data *nic_data = efx_pf->nic_data; | 3960 | struct efx_ef10_nic_data *nic_data = efx_pf->nic_data; |
3862 | unsigned int i; | 3961 | unsigned int i; |
3863 | 3962 | ||
3963 | /* MAC address successfully changed by VF (with MAC | ||
3964 | * spoofing) so update the parent PF if possible. | ||
3965 | */ | ||
3864 | for (i = 0; i < efx_pf->vf_count; ++i) { | 3966 | for (i = 0; i < efx_pf->vf_count; ++i) { |
3865 | struct ef10_vf *vf = nic_data->vf + i; | 3967 | struct ef10_vf *vf = nic_data->vf + i; |
3866 | 3968 | ||
@@ -3871,8 +3973,24 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) | |||
3871 | } | 3973 | } |
3872 | } | 3974 | } |
3873 | } | 3975 | } |
3874 | } | 3976 | } else |
3875 | #endif | 3977 | #endif |
3978 | if (rc == -EPERM) { | ||
3979 | netif_err(efx, drv, efx->net_dev, | ||
3980 | "Cannot change MAC address; use sfboot to enable" | ||
3981 | " mac-spoofing on this interface\n"); | ||
3982 | } else if (rc == -ENOSYS && !efx_ef10_is_vf(efx)) { | ||
3983 | /* If the active MCFW does not support MC_CMD_VADAPTOR_SET_MAC | ||
3984 | * fall-back to the method of changing the MAC address on the | ||
3985 | * vport. This only applies to PFs because such versions of | ||
3986 | * MCFW do not support VFs. | ||
3987 | */ | ||
3988 | rc = efx_ef10_vport_set_mac_address(efx); | ||
3989 | } else { | ||
3990 | efx_mcdi_display_error(efx, MC_CMD_VADAPTOR_SET_MAC, | ||
3991 | sizeof(inbuf), NULL, 0, rc); | ||
3992 | } | ||
3993 | |||
3876 | return rc; | 3994 | return rc; |
3877 | } | 3995 | } |
3878 | 3996 | ||
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 6c9b6e45509a..7485f71b4e2f 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c | |||
@@ -29,30 +29,6 @@ static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id, | |||
29 | NULL, 0, NULL); | 29 | NULL, 0, NULL); |
30 | } | 30 | } |
31 | 31 | ||
32 | static int efx_ef10_vport_add_mac(struct efx_nic *efx, | ||
33 | unsigned int port_id, u8 *mac) | ||
34 | { | ||
35 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN); | ||
36 | |||
37 | MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id); | ||
38 | ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac); | ||
39 | |||
40 | return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf, | ||
41 | sizeof(inbuf), NULL, 0, NULL); | ||
42 | } | ||
43 | |||
44 | static int efx_ef10_vport_del_mac(struct efx_nic *efx, | ||
45 | unsigned int port_id, u8 *mac) | ||
46 | { | ||
47 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); | ||
48 | |||
49 | MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); | ||
50 | ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); | ||
51 | |||
52 | return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, | ||
53 | sizeof(inbuf), NULL, 0, NULL); | ||
54 | } | ||
55 | |||
56 | static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, | 32 | static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, |
57 | unsigned int vswitch_type) | 33 | unsigned int vswitch_type) |
58 | { | 34 | { |
@@ -136,24 +112,6 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) | |||
136 | NULL, 0, NULL); | 112 | NULL, 0, NULL); |
137 | } | 113 | } |
138 | 114 | ||
139 | static int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id) | ||
140 | { | ||
141 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN); | ||
142 | |||
143 | MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); | ||
144 | return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf), | ||
145 | NULL, 0, NULL); | ||
146 | } | ||
147 | |||
148 | static int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id) | ||
149 | { | ||
150 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN); | ||
151 | |||
152 | MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); | ||
153 | return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf), | ||
154 | NULL, 0, NULL); | ||
155 | } | ||
156 | |||
157 | static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) | 115 | static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) |
158 | { | 116 | { |
159 | struct efx_ef10_nic_data *nic_data = efx->nic_data; | 117 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index db4ef537c610..6d25b92cb45e 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h | |||
@@ -65,5 +65,11 @@ int efx_ef10_vswitching_restore_pf(struct efx_nic *efx); | |||
65 | int efx_ef10_vswitching_restore_vf(struct efx_nic *efx); | 65 | int efx_ef10_vswitching_restore_vf(struct efx_nic *efx); |
66 | void efx_ef10_vswitching_remove_pf(struct efx_nic *efx); | 66 | void efx_ef10_vswitching_remove_pf(struct efx_nic *efx); |
67 | void efx_ef10_vswitching_remove_vf(struct efx_nic *efx); | 67 | void efx_ef10_vswitching_remove_vf(struct efx_nic *efx); |
68 | int efx_ef10_vport_add_mac(struct efx_nic *efx, | ||
69 | unsigned int port_id, u8 *mac); | ||
70 | int efx_ef10_vport_del_mac(struct efx_nic *efx, | ||
71 | unsigned int port_id, u8 *mac); | ||
72 | int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id); | ||
73 | int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id); | ||
68 | 74 | ||
69 | #endif /* EF10_SRIOV_H */ | 75 | #endif /* EF10_SRIOV_H */ |