Commit | Line | Data |
---|---|---|
d4fd0404 CM |
1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
2 | /* Copyright 2017-2019 NXP */ | |
3 | ||
4 | #include <linux/module.h> | |
6517798d | 5 | #include <linux/fsl/enetc_mdio.h> |
d4fd0404 CM |
6 | #include <linux/of_mdio.h> |
7 | #include <linux/of_net.h> | |
8 | #include "enetc_pf.h" | |
9 | ||
d4fd0404 | 10 | #define ENETC_DRV_NAME_STR "ENETC PF driver" |
d4fd0404 CM |
11 | |
12 | static void enetc_pf_get_primary_mac_addr(struct enetc_hw *hw, int si, u8 *addr) | |
13 | { | |
14 | u32 upper = __raw_readl(hw->port + ENETC_PSIPMAR0(si)); | |
15 | u16 lower = __raw_readw(hw->port + ENETC_PSIPMAR1(si)); | |
16 | ||
17 | *(u32 *)addr = upper; | |
18 | *(u16 *)(addr + 4) = lower; | |
19 | } | |
20 | ||
21 | static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si, | |
22 | const u8 *addr) | |
23 | { | |
24 | u32 upper = *(const u32 *)addr; | |
25 | u16 lower = *(const u16 *)(addr + 4); | |
26 | ||
27 | __raw_writel(upper, hw->port + ENETC_PSIPMAR0(si)); | |
28 | __raw_writew(lower, hw->port + ENETC_PSIPMAR1(si)); | |
29 | } | |
30 | ||
31 | static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr) | |
32 | { | |
33 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
34 | struct sockaddr *saddr = addr; | |
35 | ||
36 | if (!is_valid_ether_addr(saddr->sa_data)) | |
37 | return -EADDRNOTAVAIL; | |
38 | ||
39 | memcpy(ndev->dev_addr, saddr->sa_data, ndev->addr_len); | |
40 | enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data); | |
41 | ||
42 | return 0; | |
43 | } | |
44 | ||
45 | static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map) | |
46 | { | |
47 | u32 val = enetc_port_rd(hw, ENETC_PSIPVMR); | |
48 | ||
49 | val &= ~ENETC_PSIPVMR_SET_VP(ENETC_VLAN_PROMISC_MAP_ALL); | |
50 | enetc_port_wr(hw, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VP(si_map) | val); | |
51 | } | |
52 | ||
d4fd0404 CM |
53 | static void enetc_enable_si_vlan_promisc(struct enetc_pf *pf, int si_idx) |
54 | { | |
55 | pf->vlan_promisc_simap |= BIT(si_idx); | |
56 | enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap); | |
57 | } | |
58 | ||
59 | static void enetc_disable_si_vlan_promisc(struct enetc_pf *pf, int si_idx) | |
60 | { | |
61 | pf->vlan_promisc_simap &= ~BIT(si_idx); | |
62 | enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap); | |
63 | } | |
64 | ||
65 | static void enetc_set_isol_vlan(struct enetc_hw *hw, int si, u16 vlan, u8 qos) | |
66 | { | |
67 | u32 val = 0; | |
68 | ||
69 | if (vlan) | |
70 | val = ENETC_PSIVLAN_EN | ENETC_PSIVLAN_SET_QOS(qos) | vlan; | |
71 | ||
72 | enetc_port_wr(hw, ENETC_PSIVLANR(si), val); | |
73 | } | |
74 | ||
75 | static int enetc_mac_addr_hash_idx(const u8 *addr) | |
76 | { | |
77 | u64 fold = __swab64(ether_addr_to_u64(addr)) >> 16; | |
78 | u64 mask = 0; | |
79 | int res = 0; | |
80 | int i; | |
81 | ||
82 | for (i = 0; i < 8; i++) | |
83 | mask |= BIT_ULL(i * 6); | |
84 | ||
85 | for (i = 0; i < 6; i++) | |
86 | res |= (hweight64(fold & (mask << i)) & 0x1) << i; | |
87 | ||
88 | return res; | |
89 | } | |
90 | ||
91 | static void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter) | |
92 | { | |
93 | filter->mac_addr_cnt = 0; | |
94 | ||
95 | bitmap_zero(filter->mac_hash_table, | |
96 | ENETC_MADDR_HASH_TBL_SZ); | |
97 | } | |
98 | ||
99 | static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter, | |
100 | const unsigned char *addr) | |
101 | { | |
102 | /* add exact match addr */ | |
103 | ether_addr_copy(filter->mac_addr, addr); | |
104 | filter->mac_addr_cnt++; | |
105 | } | |
106 | ||
107 | static void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter, | |
108 | const unsigned char *addr) | |
109 | { | |
110 | int idx = enetc_mac_addr_hash_idx(addr); | |
111 | ||
112 | /* add hash table entry */ | |
113 | __set_bit(idx, filter->mac_hash_table); | |
114 | filter->mac_addr_cnt++; | |
115 | } | |
116 | ||
117 | static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type) | |
118 | { | |
119 | bool err = si->errata & ENETC_ERR_UCMCSWP; | |
120 | ||
121 | if (type == UC) { | |
122 | enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0); | |
123 | enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0); | |
124 | } else { /* MC */ | |
125 | enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0); | |
126 | enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0); | |
127 | } | |
128 | } | |
129 | ||
130 | static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type, | |
131 | u32 *hash) | |
132 | { | |
133 | bool err = si->errata & ENETC_ERR_UCMCSWP; | |
134 | ||
135 | if (type == UC) { | |
136 | enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), *hash); | |
137 | enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), *(hash + 1)); | |
138 | } else { /* MC */ | |
139 | enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), *hash); | |
140 | enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), *(hash + 1)); | |
141 | } | |
142 | } | |
143 | ||
144 | static void enetc_sync_mac_filters(struct enetc_pf *pf) | |
145 | { | |
146 | struct enetc_mac_filter *f = pf->mac_filter; | |
147 | struct enetc_si *si = pf->si; | |
148 | int i, pos; | |
149 | ||
150 | pos = EMETC_MAC_ADDR_FILT_RES; | |
151 | ||
152 | for (i = 0; i < MADDR_TYPE; i++, f++) { | |
153 | bool em = (f->mac_addr_cnt == 1) && (i == UC); | |
154 | bool clear = !f->mac_addr_cnt; | |
155 | ||
156 | if (clear) { | |
157 | if (i == UC) | |
158 | enetc_clear_mac_flt_entry(si, pos); | |
159 | ||
160 | enetc_clear_mac_ht_flt(si, 0, i); | |
161 | continue; | |
162 | } | |
163 | ||
164 | /* exact match filter */ | |
165 | if (em) { | |
166 | int err; | |
167 | ||
168 | enetc_clear_mac_ht_flt(si, 0, UC); | |
169 | ||
170 | err = enetc_set_mac_flt_entry(si, pos, f->mac_addr, | |
171 | BIT(0)); | |
172 | if (!err) | |
173 | continue; | |
174 | ||
175 | /* fallback to HT filtering */ | |
176 | dev_warn(&si->pdev->dev, "fallback to HT filt (%d)\n", | |
177 | err); | |
178 | } | |
179 | ||
180 | /* hash table filter, clear EM filter for UC entries */ | |
181 | if (i == UC) | |
182 | enetc_clear_mac_flt_entry(si, pos); | |
183 | ||
184 | enetc_set_mac_ht_flt(si, 0, i, (u32 *)f->mac_hash_table); | |
185 | } | |
186 | } | |
187 | ||
188 | static void enetc_pf_set_rx_mode(struct net_device *ndev) | |
189 | { | |
190 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
191 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
7070eea5 | 192 | char vlan_promisc_simap = pf->vlan_promisc_simap; |
d4fd0404 CM |
193 | struct enetc_hw *hw = &priv->si->hw; |
194 | bool uprom = false, mprom = false; | |
195 | struct enetc_mac_filter *filter; | |
196 | struct netdev_hw_addr *ha; | |
197 | u32 psipmr = 0; | |
198 | bool em; | |
199 | ||
200 | if (ndev->flags & IFF_PROMISC) { | |
201 | /* enable promisc mode for SI0 (PF) */ | |
202 | psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0); | |
203 | uprom = true; | |
204 | mprom = true; | |
7070eea5 VO |
205 | /* Enable VLAN promiscuous mode for SI0 (PF) */ |
206 | vlan_promisc_simap |= BIT(0); | |
d4fd0404 CM |
207 | } else if (ndev->flags & IFF_ALLMULTI) { |
208 | /* enable multi cast promisc mode for SI0 (PF) */ | |
209 | psipmr = ENETC_PSIPMR_SET_MP(0); | |
210 | mprom = true; | |
211 | } | |
212 | ||
7070eea5 VO |
213 | enetc_set_vlan_promisc(&pf->si->hw, vlan_promisc_simap); |
214 | ||
d4fd0404 CM |
215 | /* first 2 filter entries belong to PF */ |
216 | if (!uprom) { | |
217 | /* Update unicast filters */ | |
218 | filter = &pf->mac_filter[UC]; | |
219 | enetc_reset_mac_addr_filter(filter); | |
220 | ||
221 | em = (netdev_uc_count(ndev) == 1); | |
222 | netdev_for_each_uc_addr(ha, ndev) { | |
223 | if (em) { | |
224 | enetc_add_mac_addr_em_filter(filter, ha->addr); | |
225 | break; | |
226 | } | |
227 | ||
228 | enetc_add_mac_addr_ht_filter(filter, ha->addr); | |
229 | } | |
230 | } | |
231 | ||
232 | if (!mprom) { | |
233 | /* Update multicast filters */ | |
234 | filter = &pf->mac_filter[MC]; | |
235 | enetc_reset_mac_addr_filter(filter); | |
236 | ||
237 | netdev_for_each_mc_addr(ha, ndev) { | |
238 | if (!is_multicast_ether_addr(ha->addr)) | |
239 | continue; | |
240 | ||
241 | enetc_add_mac_addr_ht_filter(filter, ha->addr); | |
242 | } | |
243 | } | |
244 | ||
245 | if (!uprom || !mprom) | |
246 | /* update PF entries */ | |
247 | enetc_sync_mac_filters(pf); | |
248 | ||
249 | psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) & | |
250 | ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0)); | |
251 | enetc_port_wr(hw, ENETC_PSIPMR, psipmr); | |
252 | } | |
253 | ||
254 | static void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx, | |
255 | u32 *hash) | |
256 | { | |
257 | enetc_port_wr(hw, ENETC_PSIVHFR0(si_idx), *hash); | |
258 | enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), *(hash + 1)); | |
259 | } | |
260 | ||
261 | static int enetc_vid_hash_idx(unsigned int vid) | |
262 | { | |
263 | int res = 0; | |
264 | int i; | |
265 | ||
266 | for (i = 0; i < 6; i++) | |
267 | res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i; | |
268 | ||
269 | return res; | |
270 | } | |
271 | ||
272 | static void enetc_sync_vlan_ht_filter(struct enetc_pf *pf, bool rehash) | |
273 | { | |
274 | int i; | |
275 | ||
276 | if (rehash) { | |
277 | bitmap_zero(pf->vlan_ht_filter, ENETC_VLAN_HT_SIZE); | |
278 | ||
279 | for_each_set_bit(i, pf->active_vlans, VLAN_N_VID) { | |
280 | int hidx = enetc_vid_hash_idx(i); | |
281 | ||
282 | __set_bit(hidx, pf->vlan_ht_filter); | |
283 | } | |
284 | } | |
285 | ||
286 | enetc_set_vlan_ht_filter(&pf->si->hw, 0, (u32 *)pf->vlan_ht_filter); | |
287 | } | |
288 | ||
289 | static int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid) | |
290 | { | |
291 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
292 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
293 | int idx; | |
294 | ||
d4fd0404 CM |
295 | __set_bit(vid, pf->active_vlans); |
296 | ||
297 | idx = enetc_vid_hash_idx(vid); | |
298 | if (!__test_and_set_bit(idx, pf->vlan_ht_filter)) | |
299 | enetc_sync_vlan_ht_filter(pf, false); | |
300 | ||
301 | return 0; | |
302 | } | |
303 | ||
304 | static int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid) | |
305 | { | |
306 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
307 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
308 | ||
309 | __clear_bit(vid, pf->active_vlans); | |
310 | enetc_sync_vlan_ht_filter(pf, true); | |
311 | ||
d4fd0404 CM |
312 | return 0; |
313 | } | |
314 | ||
315 | static void enetc_set_loopback(struct net_device *ndev, bool en) | |
316 | { | |
317 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
318 | struct enetc_hw *hw = &priv->si->hw; | |
319 | u32 reg; | |
320 | ||
321 | reg = enetc_port_rd(hw, ENETC_PM0_IF_MODE); | |
322 | if (reg & ENETC_PMO_IFM_RG) { | |
323 | /* RGMII mode */ | |
324 | reg = (reg & ~ENETC_PM0_IFM_RLP) | | |
325 | (en ? ENETC_PM0_IFM_RLP : 0); | |
326 | enetc_port_wr(hw, ENETC_PM0_IF_MODE, reg); | |
327 | } else { | |
328 | /* assume SGMII mode */ | |
329 | reg = enetc_port_rd(hw, ENETC_PM0_CMD_CFG); | |
330 | reg = (reg & ~ENETC_PM0_CMD_XGLP) | | |
331 | (en ? ENETC_PM0_CMD_XGLP : 0); | |
332 | reg = (reg & ~ENETC_PM0_CMD_PHY_TX_EN) | | |
333 | (en ? ENETC_PM0_CMD_PHY_TX_EN : 0); | |
334 | enetc_port_wr(hw, ENETC_PM0_CMD_CFG, reg); | |
335 | enetc_port_wr(hw, ENETC_PM1_CMD_CFG, reg); | |
336 | } | |
337 | } | |
338 | ||
339 | static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac) | |
340 | { | |
341 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
342 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
beb74ac8 | 343 | struct enetc_vf_state *vf_state; |
d4fd0404 CM |
344 | |
345 | if (vf >= pf->total_vfs) | |
346 | return -EINVAL; | |
347 | ||
348 | if (!is_valid_ether_addr(mac)) | |
349 | return -EADDRNOTAVAIL; | |
350 | ||
beb74ac8 CM |
351 | vf_state = &pf->vf_state[vf]; |
352 | vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC; | |
d4fd0404 CM |
353 | enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac); |
354 | return 0; | |
355 | } | |
356 | ||
357 | static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, | |
358 | u8 qos, __be16 proto) | |
359 | { | |
360 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
361 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
362 | ||
363 | if (priv->si->errata & ENETC_ERR_VLAN_ISOL) | |
364 | return -EOPNOTSUPP; | |
365 | ||
366 | if (vf >= pf->total_vfs) | |
367 | return -EINVAL; | |
368 | ||
369 | if (proto != htons(ETH_P_8021Q)) | |
370 | /* only C-tags supported for now */ | |
371 | return -EPROTONOSUPPORT; | |
372 | ||
373 | enetc_set_isol_vlan(&priv->si->hw, vf + 1, vlan, qos); | |
374 | return 0; | |
375 | } | |
376 | ||
377 | static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en) | |
378 | { | |
379 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
380 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
381 | u32 cfgr; | |
382 | ||
383 | if (vf >= pf->total_vfs) | |
384 | return -EINVAL; | |
385 | ||
386 | cfgr = enetc_port_rd(&priv->si->hw, ENETC_PSICFGR0(vf + 1)); | |
387 | cfgr = (cfgr & ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0); | |
388 | enetc_port_wr(&priv->si->hw, ENETC_PSICFGR0(vf + 1), cfgr); | |
389 | ||
390 | return 0; | |
391 | } | |
392 | ||
393 | static void enetc_port_setup_primary_mac_address(struct enetc_si *si) | |
394 | { | |
395 | unsigned char mac_addr[MAX_ADDR_LEN]; | |
396 | struct enetc_pf *pf = enetc_si_priv(si); | |
397 | struct enetc_hw *hw = &si->hw; | |
398 | int i; | |
399 | ||
400 | /* check MAC addresses for PF and all VFs, if any is 0 set it ro rand */ | |
401 | for (i = 0; i < pf->total_vfs + 1; i++) { | |
402 | enetc_pf_get_primary_mac_addr(hw, i, mac_addr); | |
403 | if (!is_zero_ether_addr(mac_addr)) | |
404 | continue; | |
405 | eth_random_addr(mac_addr); | |
406 | dev_info(&si->pdev->dev, "no MAC address specified for SI%d, using %pM\n", | |
407 | i, mac_addr); | |
408 | enetc_pf_set_primary_mac_addr(hw, i, mac_addr); | |
409 | } | |
410 | } | |
411 | ||
d382563f CM |
412 | static void enetc_port_assign_rfs_entries(struct enetc_si *si) |
413 | { | |
414 | struct enetc_pf *pf = enetc_si_priv(si); | |
415 | struct enetc_hw *hw = &si->hw; | |
416 | int num_entries, vf_entries, i; | |
417 | u32 val; | |
418 | ||
419 | /* split RFS entries between functions */ | |
420 | val = enetc_port_rd(hw, ENETC_PRFSCAPR); | |
421 | num_entries = ENETC_PRFSCAPR_GET_NUM_RFS(val); | |
422 | vf_entries = num_entries / (pf->total_vfs + 1); | |
423 | ||
424 | for (i = 0; i < pf->total_vfs; i++) | |
425 | enetc_port_wr(hw, ENETC_PSIRFSCFGR(i + 1), vf_entries); | |
426 | enetc_port_wr(hw, ENETC_PSIRFSCFGR(0), | |
427 | num_entries - vf_entries * pf->total_vfs); | |
428 | ||
429 | /* enable RFS on port */ | |
430 | enetc_port_wr(hw, ENETC_PRFSMR, ENETC_PRFSMR_RFSE); | |
431 | } | |
432 | ||
d4fd0404 CM |
433 | static void enetc_port_si_configure(struct enetc_si *si) |
434 | { | |
435 | struct enetc_pf *pf = enetc_si_priv(si); | |
436 | struct enetc_hw *hw = &si->hw; | |
437 | int num_rings, i; | |
438 | u32 val; | |
439 | ||
440 | val = enetc_port_rd(hw, ENETC_PCAPR0); | |
441 | num_rings = min(ENETC_PCAPR0_RXBDR(val), ENETC_PCAPR0_TXBDR(val)); | |
442 | ||
443 | val = ENETC_PSICFGR0_SET_TXBDR(ENETC_PF_NUM_RINGS); | |
444 | val |= ENETC_PSICFGR0_SET_RXBDR(ENETC_PF_NUM_RINGS); | |
445 | ||
446 | if (unlikely(num_rings < ENETC_PF_NUM_RINGS)) { | |
447 | val = ENETC_PSICFGR0_SET_TXBDR(num_rings); | |
448 | val |= ENETC_PSICFGR0_SET_RXBDR(num_rings); | |
449 | ||
450 | dev_warn(&si->pdev->dev, "Found %d rings, expected %d!\n", | |
451 | num_rings, ENETC_PF_NUM_RINGS); | |
452 | ||
453 | num_rings = 0; | |
454 | } | |
455 | ||
456 | /* Add default one-time settings for SI0 (PF) */ | |
457 | val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S); | |
458 | ||
459 | enetc_port_wr(hw, ENETC_PSICFGR0(0), val); | |
460 | ||
461 | if (num_rings) | |
462 | num_rings -= ENETC_PF_NUM_RINGS; | |
463 | ||
464 | /* Configure the SIs for each available VF */ | |
465 | val = ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S); | |
466 | val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE; | |
467 | ||
468 | if (num_rings) { | |
469 | num_rings /= pf->total_vfs; | |
470 | val |= ENETC_PSICFGR0_SET_TXBDR(num_rings); | |
471 | val |= ENETC_PSICFGR0_SET_RXBDR(num_rings); | |
472 | } | |
473 | ||
474 | for (i = 0; i < pf->total_vfs; i++) | |
475 | enetc_port_wr(hw, ENETC_PSICFGR0(i + 1), val); | |
476 | ||
477 | /* Port level VLAN settings */ | |
478 | val = ENETC_PVCLCTR_OVTPIDL(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S); | |
479 | enetc_port_wr(hw, ENETC_PVCLCTR, val); | |
480 | /* use outer tag for VLAN filtering */ | |
481 | enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS); | |
482 | } | |
483 | ||
484 | static void enetc_configure_port_mac(struct enetc_hw *hw) | |
485 | { | |
486 | enetc_port_wr(hw, ENETC_PM0_MAXFRM, | |
487 | ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE)); | |
488 | ||
489 | enetc_port_wr(hw, ENETC_PTCMSDUR(0), ENETC_MAC_MAXFRM_SIZE); | |
490 | enetc_port_wr(hw, ENETC_PTXMBAR, 2 * ENETC_MAC_MAXFRM_SIZE); | |
491 | ||
492 | enetc_port_wr(hw, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN | | |
493 | ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC | | |
494 | ENETC_PM0_TX_EN | ENETC_PM0_RX_EN); | |
495 | ||
496 | enetc_port_wr(hw, ENETC_PM1_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN | | |
497 | ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC | | |
498 | ENETC_PM0_TX_EN | ENETC_PM0_RX_EN); | |
499 | /* set auto-speed for RGMII */ | |
500 | if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG) | |
501 | enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO); | |
502 | if (enetc_global_rd(hw, ENETC_G_EPFBLPR(1)) == ENETC_G_EPFBLPR1_XGMII) | |
503 | enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII); | |
504 | } | |
505 | ||
506 | static void enetc_configure_port_pmac(struct enetc_hw *hw) | |
507 | { | |
508 | u32 temp; | |
509 | ||
510 | /* Set pMAC step lock */ | |
511 | temp = enetc_port_rd(hw, ENETC_PFPMR); | |
512 | enetc_port_wr(hw, ENETC_PFPMR, | |
513 | temp | ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM); | |
514 | ||
515 | temp = enetc_port_rd(hw, ENETC_MMCSR); | |
516 | enetc_port_wr(hw, ENETC_MMCSR, temp | ENETC_MMCSR_ME); | |
517 | } | |
518 | ||
519 | static void enetc_configure_port(struct enetc_pf *pf) | |
520 | { | |
d382563f | 521 | u8 hash_key[ENETC_RSSHASH_KEY_SIZE]; |
d4fd0404 CM |
522 | struct enetc_hw *hw = &pf->si->hw; |
523 | ||
524 | enetc_configure_port_pmac(hw); | |
525 | ||
526 | enetc_configure_port_mac(hw); | |
527 | ||
528 | enetc_port_si_configure(pf->si); | |
529 | ||
d382563f CM |
530 | /* set up hash key */ |
531 | get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE); | |
532 | enetc_set_rss_key(hw, hash_key); | |
533 | ||
534 | /* split up RFS entries */ | |
535 | enetc_port_assign_rfs_entries(pf->si); | |
536 | ||
d4fd0404 CM |
537 | /* fix-up primary MAC addresses, if not set already */ |
538 | enetc_port_setup_primary_mac_address(pf->si); | |
539 | ||
540 | /* enforce VLAN promisc mode for all SIs */ | |
541 | pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL; | |
542 | enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap); | |
543 | ||
544 | enetc_port_wr(hw, ENETC_PSIPMR, 0); | |
545 | ||
546 | /* enable port */ | |
547 | enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN); | |
548 | } | |
549 | ||
beb74ac8 CM |
550 | /* Messaging */ |
551 | static u16 enetc_msg_pf_set_vf_primary_mac_addr(struct enetc_pf *pf, | |
552 | int vf_id) | |
553 | { | |
554 | struct enetc_vf_state *vf_state = &pf->vf_state[vf_id]; | |
555 | struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id]; | |
556 | struct enetc_msg_cmd_set_primary_mac *cmd; | |
557 | struct device *dev = &pf->si->pdev->dev; | |
558 | u16 cmd_id; | |
559 | char *addr; | |
560 | ||
561 | cmd = (struct enetc_msg_cmd_set_primary_mac *)msg->vaddr; | |
562 | cmd_id = cmd->header.id; | |
563 | if (cmd_id != ENETC_MSG_CMD_MNG_ADD) | |
564 | return ENETC_MSG_CMD_STATUS_FAIL; | |
565 | ||
566 | addr = cmd->mac.sa_data; | |
567 | if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) | |
568 | dev_warn(dev, "Attempt to override PF set mac addr for VF%d\n", | |
569 | vf_id); | |
570 | else | |
571 | enetc_pf_set_primary_mac_addr(&pf->si->hw, vf_id + 1, addr); | |
572 | ||
573 | return ENETC_MSG_CMD_STATUS_OK; | |
574 | } | |
575 | ||
576 | void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status) | |
577 | { | |
578 | struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id]; | |
579 | struct device *dev = &pf->si->pdev->dev; | |
580 | struct enetc_msg_cmd_header *cmd_hdr; | |
581 | u16 cmd_type; | |
582 | ||
583 | *status = ENETC_MSG_CMD_STATUS_OK; | |
584 | cmd_hdr = (struct enetc_msg_cmd_header *)msg->vaddr; | |
585 | cmd_type = cmd_hdr->type; | |
586 | ||
587 | switch (cmd_type) { | |
588 | case ENETC_MSG_CMD_MNG_MAC: | |
589 | *status = enetc_msg_pf_set_vf_primary_mac_addr(pf, vf_id); | |
590 | break; | |
591 | default: | |
592 | dev_err(dev, "command not supported (cmd_type: 0x%x)\n", | |
593 | cmd_type); | |
594 | } | |
595 | } | |
596 | ||
d4fd0404 CM |
597 | #ifdef CONFIG_PCI_IOV |
598 | static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs) | |
599 | { | |
600 | struct enetc_si *si = pci_get_drvdata(pdev); | |
601 | struct enetc_pf *pf = enetc_si_priv(si); | |
602 | int err; | |
603 | ||
604 | if (!num_vfs) { | |
beb74ac8 CM |
605 | enetc_msg_psi_free(pf); |
606 | kfree(pf->vf_state); | |
d4fd0404 CM |
607 | pf->num_vfs = 0; |
608 | pci_disable_sriov(pdev); | |
609 | } else { | |
610 | pf->num_vfs = num_vfs; | |
611 | ||
beb74ac8 CM |
612 | pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state), |
613 | GFP_KERNEL); | |
614 | if (!pf->vf_state) { | |
615 | pf->num_vfs = 0; | |
616 | return -ENOMEM; | |
617 | } | |
618 | ||
619 | err = enetc_msg_psi_init(pf); | |
620 | if (err) { | |
621 | dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err); | |
622 | goto err_msg_psi; | |
623 | } | |
624 | ||
d4fd0404 CM |
625 | err = pci_enable_sriov(pdev, num_vfs); |
626 | if (err) { | |
627 | dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err); | |
628 | goto err_en_sriov; | |
629 | } | |
630 | } | |
631 | ||
632 | return num_vfs; | |
633 | ||
634 | err_en_sriov: | |
beb74ac8 CM |
635 | enetc_msg_psi_free(pf); |
636 | err_msg_psi: | |
637 | kfree(pf->vf_state); | |
d4fd0404 CM |
638 | pf->num_vfs = 0; |
639 | ||
640 | return err; | |
641 | } | |
642 | #else | |
643 | #define enetc_sriov_configure(pdev, num_vfs) (void)0 | |
644 | #endif | |
645 | ||
646 | static int enetc_pf_set_features(struct net_device *ndev, | |
647 | netdev_features_t features) | |
648 | { | |
649 | netdev_features_t changed = ndev->features ^ features; | |
650 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
651 | ||
7070eea5 VO |
652 | if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { |
653 | struct enetc_pf *pf = enetc_si_priv(priv->si); | |
654 | ||
655 | if (!!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) | |
656 | enetc_disable_si_vlan_promisc(pf, 0); | |
657 | else | |
658 | enetc_enable_si_vlan_promisc(pf, 0); | |
659 | } | |
660 | ||
d4fd0404 CM |
661 | if (changed & NETIF_F_LOOPBACK) |
662 | enetc_set_loopback(ndev, !!(features & NETIF_F_LOOPBACK)); | |
663 | ||
d382563f | 664 | return enetc_set_features(ndev, features); |
d4fd0404 CM |
665 | } |
666 | ||
667 | static const struct net_device_ops enetc_ndev_ops = { | |
668 | .ndo_open = enetc_open, | |
669 | .ndo_stop = enetc_close, | |
670 | .ndo_start_xmit = enetc_xmit, | |
671 | .ndo_get_stats = enetc_get_stats, | |
672 | .ndo_set_mac_address = enetc_pf_set_mac_addr, | |
673 | .ndo_set_rx_mode = enetc_pf_set_rx_mode, | |
674 | .ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid, | |
675 | .ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid, | |
676 | .ndo_set_vf_mac = enetc_pf_set_vf_mac, | |
677 | .ndo_set_vf_vlan = enetc_pf_set_vf_vlan, | |
678 | .ndo_set_vf_spoofchk = enetc_pf_set_vf_spoofchk, | |
679 | .ndo_set_features = enetc_pf_set_features, | |
d3982312 | 680 | .ndo_do_ioctl = enetc_ioctl, |
cbe9e835 | 681 | .ndo_setup_tc = enetc_setup_tc, |
d4fd0404 CM |
682 | }; |
683 | ||
684 | static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, | |
685 | const struct net_device_ops *ndev_ops) | |
686 | { | |
687 | struct enetc_ndev_priv *priv = netdev_priv(ndev); | |
688 | ||
689 | SET_NETDEV_DEV(ndev, &si->pdev->dev); | |
690 | priv->ndev = ndev; | |
691 | priv->si = si; | |
692 | priv->dev = &si->pdev->dev; | |
693 | si->ndev = ndev; | |
694 | ||
695 | priv->msg_enable = (NETIF_MSG_WOL << 1) - 1; | |
696 | ndev->netdev_ops = ndev_ops; | |
697 | enetc_set_ethtool_ops(ndev); | |
698 | ndev->watchdog_timeo = 5 * HZ; | |
699 | ndev->max_mtu = ENETC_MAX_MTU; | |
700 | ||
5d91eebc | 701 | ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_HW_CSUM | |
d4fd0404 | 702 | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | |
7070eea5 | 703 | NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK; |
d4fd0404 CM |
704 | ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | |
705 | NETIF_F_RXCSUM | NETIF_F_HW_CSUM | | |
706 | NETIF_F_HW_VLAN_CTAG_TX | | |
7070eea5 | 707 | NETIF_F_HW_VLAN_CTAG_RX; |
d4fd0404 | 708 | |
d382563f CM |
709 | if (si->num_rss) |
710 | ndev->hw_features |= NETIF_F_RXHASH; | |
711 | ||
d4fd0404 CM |
712 | if (si->errata & ENETC_ERR_TXCSUM) { |
713 | ndev->hw_features &= ~NETIF_F_HW_CSUM; | |
714 | ndev->features &= ~NETIF_F_HW_CSUM; | |
715 | } | |
716 | ||
717 | ndev->priv_flags |= IFF_UNICAST_FLT; | |
718 | ||
2e47cb41 PL |
719 | if (si->hw_features & ENETC_SI_F_QBV) |
720 | priv->active_offloads |= ENETC_F_QBV; | |
721 | ||
888ae5a3 | 722 | if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) { |
79e49982 PL |
723 | priv->active_offloads |= ENETC_F_QCI; |
724 | ndev->features |= NETIF_F_HW_TC; | |
725 | ndev->hw_features |= NETIF_F_HW_TC; | |
79e49982 PL |
726 | } |
727 | ||
d4fd0404 CM |
728 | /* pick up primary MAC address from SI */ |
729 | enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr); | |
730 | } | |
731 | ||
6517798d CM |
732 | static int enetc_mdio_probe(struct enetc_pf *pf) |
733 | { | |
734 | struct device *dev = &pf->si->pdev->dev; | |
735 | struct enetc_mdio_priv *mdio_priv; | |
736 | struct device_node *np; | |
737 | struct mii_bus *bus; | |
738 | int err; | |
739 | ||
740 | bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); | |
741 | if (!bus) | |
742 | return -ENOMEM; | |
743 | ||
744 | bus->name = "Freescale ENETC MDIO Bus"; | |
745 | bus->read = enetc_mdio_read; | |
746 | bus->write = enetc_mdio_write; | |
747 | bus->parent = dev; | |
748 | mdio_priv = bus->priv; | |
749 | mdio_priv->hw = &pf->si->hw; | |
750 | mdio_priv->mdio_base = ENETC_EMDIO_BASE; | |
751 | snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); | |
752 | ||
753 | np = of_get_child_by_name(dev->of_node, "mdio"); | |
754 | if (!np) { | |
755 | dev_err(dev, "MDIO node missing\n"); | |
756 | return -EINVAL; | |
757 | } | |
758 | ||
759 | err = of_mdiobus_register(bus, np); | |
760 | if (err) { | |
761 | of_node_put(np); | |
762 | dev_err(dev, "cannot register MDIO bus\n"); | |
763 | return err; | |
764 | } | |
765 | ||
766 | of_node_put(np); | |
767 | pf->mdio = bus; | |
768 | ||
769 | return 0; | |
770 | } | |
771 | ||
772 | static void enetc_mdio_remove(struct enetc_pf *pf) | |
773 | { | |
774 | if (pf->mdio) | |
775 | mdiobus_unregister(pf->mdio); | |
776 | } | |
777 | ||
d4fd0404 CM |
778 | static int enetc_of_get_phy(struct enetc_ndev_priv *priv) |
779 | { | |
ebfcb23d | 780 | struct enetc_pf *pf = enetc_si_priv(priv->si); |
d4fd0404 | 781 | struct device_node *np = priv->dev->of_node; |
231ece36 | 782 | struct device_node *mdio_np; |
d4fd0404 CM |
783 | int err; |
784 | ||
d4fd0404 CM |
785 | priv->phy_node = of_parse_phandle(np, "phy-handle", 0); |
786 | if (!priv->phy_node) { | |
787 | if (!of_phy_is_fixed_link(np)) { | |
788 | dev_err(priv->dev, "PHY not specified\n"); | |
789 | return -ENODEV; | |
790 | } | |
791 | ||
792 | err = of_phy_register_fixed_link(np); | |
793 | if (err < 0) { | |
794 | dev_err(priv->dev, "fixed link registration failed\n"); | |
795 | return err; | |
796 | } | |
797 | ||
798 | priv->phy_node = of_node_get(np); | |
799 | } | |
800 | ||
231ece36 CM |
801 | mdio_np = of_get_child_by_name(np, "mdio"); |
802 | if (mdio_np) { | |
803 | of_node_put(mdio_np); | |
ebfcb23d CM |
804 | err = enetc_mdio_probe(pf); |
805 | if (err) { | |
806 | of_node_put(priv->phy_node); | |
807 | return err; | |
808 | } | |
809 | } | |
810 | ||
0c65b2b9 AL |
811 | err = of_get_phy_mode(np, &priv->if_mode); |
812 | if (err) { | |
d4fd0404 CM |
813 | dev_err(priv->dev, "missing phy type\n"); |
814 | of_node_put(priv->phy_node); | |
815 | if (of_phy_is_fixed_link(np)) | |
816 | of_phy_deregister_fixed_link(np); | |
ebfcb23d CM |
817 | else |
818 | enetc_mdio_remove(pf); | |
d4fd0404 CM |
819 | |
820 | return -EINVAL; | |
821 | } | |
822 | ||
823 | return 0; | |
824 | } | |
825 | ||
826 | static void enetc_of_put_phy(struct enetc_ndev_priv *priv) | |
827 | { | |
828 | struct device_node *np = priv->dev->of_node; | |
829 | ||
830 | if (np && of_phy_is_fixed_link(np)) | |
831 | of_phy_deregister_fixed_link(np); | |
832 | if (priv->phy_node) | |
833 | of_node_put(priv->phy_node); | |
834 | } | |
835 | ||
836 | static int enetc_pf_probe(struct pci_dev *pdev, | |
837 | const struct pci_device_id *ent) | |
838 | { | |
839 | struct enetc_ndev_priv *priv; | |
840 | struct net_device *ndev; | |
841 | struct enetc_si *si; | |
842 | struct enetc_pf *pf; | |
843 | int err; | |
844 | ||
845 | if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) { | |
846 | dev_info(&pdev->dev, "device is disabled, skipping\n"); | |
847 | return -ENODEV; | |
848 | } | |
849 | ||
850 | err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf)); | |
851 | if (err) { | |
852 | dev_err(&pdev->dev, "PCI probing failed\n"); | |
853 | return err; | |
854 | } | |
855 | ||
856 | si = pci_get_drvdata(pdev); | |
857 | if (!si->hw.port || !si->hw.global) { | |
858 | err = -ENODEV; | |
859 | dev_err(&pdev->dev, "could not map PF space, probing a VF?\n"); | |
860 | goto err_map_pf_space; | |
861 | } | |
862 | ||
863 | pf = enetc_si_priv(si); | |
864 | pf->si = si; | |
865 | pf->total_vfs = pci_sriov_get_totalvfs(pdev); | |
866 | ||
867 | enetc_configure_port(pf); | |
868 | ||
869 | enetc_get_si_caps(si); | |
870 | ||
871 | ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS); | |
872 | if (!ndev) { | |
873 | err = -ENOMEM; | |
874 | dev_err(&pdev->dev, "netdev creation failed\n"); | |
875 | goto err_alloc_netdev; | |
876 | } | |
877 | ||
878 | enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops); | |
879 | ||
880 | priv = netdev_priv(ndev); | |
881 | ||
882 | enetc_init_si_rings_params(priv); | |
883 | ||
884 | err = enetc_alloc_si_resources(priv); | |
885 | if (err) { | |
886 | dev_err(&pdev->dev, "SI resource alloc failed\n"); | |
887 | goto err_alloc_si_res; | |
888 | } | |
889 | ||
890 | err = enetc_alloc_msix(priv); | |
891 | if (err) { | |
892 | dev_err(&pdev->dev, "MSIX alloc failed\n"); | |
893 | goto err_alloc_msix; | |
894 | } | |
895 | ||
896 | err = enetc_of_get_phy(priv); | |
897 | if (err) | |
898 | dev_warn(&pdev->dev, "Fallback to PHY-less operation\n"); | |
899 | ||
900 | err = register_netdev(ndev); | |
901 | if (err) | |
902 | goto err_reg_netdev; | |
903 | ||
904 | netif_carrier_off(ndev); | |
905 | ||
d4fd0404 CM |
906 | return 0; |
907 | ||
908 | err_reg_netdev: | |
26cb7085 | 909 | enetc_mdio_remove(pf); |
d4fd0404 CM |
910 | enetc_of_put_phy(priv); |
911 | enetc_free_msix(priv); | |
912 | err_alloc_msix: | |
913 | enetc_free_si_resources(priv); | |
914 | err_alloc_si_res: | |
915 | si->ndev = NULL; | |
916 | free_netdev(ndev); | |
917 | err_alloc_netdev: | |
918 | err_map_pf_space: | |
919 | enetc_pci_remove(pdev); | |
920 | ||
921 | return err; | |
922 | } | |
923 | ||
924 | static void enetc_pf_remove(struct pci_dev *pdev) | |
925 | { | |
926 | struct enetc_si *si = pci_get_drvdata(pdev); | |
927 | struct enetc_pf *pf = enetc_si_priv(si); | |
928 | struct enetc_ndev_priv *priv; | |
929 | ||
930 | if (pf->num_vfs) | |
931 | enetc_sriov_configure(pdev, 0); | |
932 | ||
933 | priv = netdev_priv(si->ndev); | |
d4fd0404 CM |
934 | unregister_netdev(si->ndev); |
935 | ||
ebfcb23d | 936 | enetc_mdio_remove(pf); |
d4fd0404 CM |
937 | enetc_of_put_phy(priv); |
938 | ||
939 | enetc_free_msix(priv); | |
940 | ||
941 | enetc_free_si_resources(priv); | |
942 | ||
943 | free_netdev(si->ndev); | |
944 | ||
945 | enetc_pci_remove(pdev); | |
946 | } | |
947 | ||
948 | static const struct pci_device_id enetc_pf_id_table[] = { | |
949 | { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) }, | |
950 | { 0, } /* End of table. */ | |
951 | }; | |
952 | MODULE_DEVICE_TABLE(pci, enetc_pf_id_table); | |
953 | ||
954 | static struct pci_driver enetc_pf_driver = { | |
955 | .name = KBUILD_MODNAME, | |
956 | .id_table = enetc_pf_id_table, | |
957 | .probe = enetc_pf_probe, | |
958 | .remove = enetc_pf_remove, | |
959 | #ifdef CONFIG_PCI_IOV | |
960 | .sriov_configure = enetc_sriov_configure, | |
961 | #endif | |
962 | }; | |
963 | module_pci_driver(enetc_pf_driver); | |
964 | ||
965 | MODULE_DESCRIPTION(ENETC_DRV_NAME_STR); | |
966 | MODULE_LICENSE("Dual BSD/GPL"); |