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