diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/net/ethernet/octeon/octeon_mgmt.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/net/ethernet/octeon/octeon_mgmt.c')
-rw-r--r-- | drivers/net/ethernet/octeon/octeon_mgmt.c | 1609 |
1 files changed, 0 insertions, 1609 deletions
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c deleted file mode 100644 index b5499198e02..00000000000 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ /dev/null | |||
@@ -1,1609 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2009-2012 Cavium, Inc | ||
7 | */ | ||
8 | |||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/etherdevice.h> | ||
12 | #include <linux/capability.h> | ||
13 | #include <linux/net_tstamp.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/if_vlan.h> | ||
18 | #include <linux/of_mdio.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of_net.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/phy.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/octeon/octeon.h> | ||
27 | #include <asm/octeon/cvmx-mixx-defs.h> | ||
28 | #include <asm/octeon/cvmx-agl-defs.h> | ||
29 | |||
30 | #define DRV_NAME "octeon_mgmt" | ||
31 | #define DRV_VERSION "2.0" | ||
32 | #define DRV_DESCRIPTION \ | ||
33 | "Cavium Networks Octeon MII (management) port Network Driver" | ||
34 | |||
35 | #define OCTEON_MGMT_NAPI_WEIGHT 16 | ||
36 | |||
37 | /* Ring sizes that are powers of two allow for more efficient modulo | ||
38 | * opertions. | ||
39 | */ | ||
40 | #define OCTEON_MGMT_RX_RING_SIZE 512 | ||
41 | #define OCTEON_MGMT_TX_RING_SIZE 128 | ||
42 | |||
43 | /* Allow 8 bytes for vlan and FCS. */ | ||
44 | #define OCTEON_MGMT_RX_HEADROOM (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN) | ||
45 | |||
46 | union mgmt_port_ring_entry { | ||
47 | u64 d64; | ||
48 | struct { | ||
49 | u64 reserved_62_63:2; | ||
50 | /* Length of the buffer/packet in bytes */ | ||
51 | u64 len:14; | ||
52 | /* For TX, signals that the packet should be timestamped */ | ||
53 | u64 tstamp:1; | ||
54 | /* The RX error code */ | ||
55 | u64 code:7; | ||
56 | #define RING_ENTRY_CODE_DONE 0xf | ||
57 | #define RING_ENTRY_CODE_MORE 0x10 | ||
58 | /* Physical address of the buffer */ | ||
59 | u64 addr:40; | ||
60 | } s; | ||
61 | }; | ||
62 | |||
63 | #define MIX_ORING1 0x0 | ||
64 | #define MIX_ORING2 0x8 | ||
65 | #define MIX_IRING1 0x10 | ||
66 | #define MIX_IRING2 0x18 | ||
67 | #define MIX_CTL 0x20 | ||
68 | #define MIX_IRHWM 0x28 | ||
69 | #define MIX_IRCNT 0x30 | ||
70 | #define MIX_ORHWM 0x38 | ||
71 | #define MIX_ORCNT 0x40 | ||
72 | #define MIX_ISR 0x48 | ||
73 | #define MIX_INTENA 0x50 | ||
74 | #define MIX_REMCNT 0x58 | ||
75 | #define MIX_BIST 0x78 | ||
76 | |||
77 | #define AGL_GMX_PRT_CFG 0x10 | ||
78 | #define AGL_GMX_RX_FRM_CTL 0x18 | ||
79 | #define AGL_GMX_RX_FRM_MAX 0x30 | ||
80 | #define AGL_GMX_RX_JABBER 0x38 | ||
81 | #define AGL_GMX_RX_STATS_CTL 0x50 | ||
82 | |||
83 | #define AGL_GMX_RX_STATS_PKTS_DRP 0xb0 | ||
84 | #define AGL_GMX_RX_STATS_OCTS_DRP 0xb8 | ||
85 | #define AGL_GMX_RX_STATS_PKTS_BAD 0xc0 | ||
86 | |||
87 | #define AGL_GMX_RX_ADR_CTL 0x100 | ||
88 | #define AGL_GMX_RX_ADR_CAM_EN 0x108 | ||
89 | #define AGL_GMX_RX_ADR_CAM0 0x180 | ||
90 | #define AGL_GMX_RX_ADR_CAM1 0x188 | ||
91 | #define AGL_GMX_RX_ADR_CAM2 0x190 | ||
92 | #define AGL_GMX_RX_ADR_CAM3 0x198 | ||
93 | #define AGL_GMX_RX_ADR_CAM4 0x1a0 | ||
94 | #define AGL_GMX_RX_ADR_CAM5 0x1a8 | ||
95 | |||
96 | #define AGL_GMX_TX_CLK 0x208 | ||
97 | #define AGL_GMX_TX_STATS_CTL 0x268 | ||
98 | #define AGL_GMX_TX_CTL 0x270 | ||
99 | #define AGL_GMX_TX_STAT0 0x280 | ||
100 | #define AGL_GMX_TX_STAT1 0x288 | ||
101 | #define AGL_GMX_TX_STAT2 0x290 | ||
102 | #define AGL_GMX_TX_STAT3 0x298 | ||
103 | #define AGL_GMX_TX_STAT4 0x2a0 | ||
104 | #define AGL_GMX_TX_STAT5 0x2a8 | ||
105 | #define AGL_GMX_TX_STAT6 0x2b0 | ||
106 | #define AGL_GMX_TX_STAT7 0x2b8 | ||
107 | #define AGL_GMX_TX_STAT8 0x2c0 | ||
108 | #define AGL_GMX_TX_STAT9 0x2c8 | ||
109 | |||
110 | struct octeon_mgmt { | ||
111 | struct net_device *netdev; | ||
112 | u64 mix; | ||
113 | u64 agl; | ||
114 | u64 agl_prt_ctl; | ||
115 | int port; | ||
116 | int irq; | ||
117 | bool has_rx_tstamp; | ||
118 | u64 *tx_ring; | ||
119 | dma_addr_t tx_ring_handle; | ||
120 | unsigned int tx_next; | ||
121 | unsigned int tx_next_clean; | ||
122 | unsigned int tx_current_fill; | ||
123 | /* The tx_list lock also protects the ring related variables */ | ||
124 | struct sk_buff_head tx_list; | ||
125 | |||
126 | /* RX variables only touched in napi_poll. No locking necessary. */ | ||
127 | u64 *rx_ring; | ||
128 | dma_addr_t rx_ring_handle; | ||
129 | unsigned int rx_next; | ||
130 | unsigned int rx_next_fill; | ||
131 | unsigned int rx_current_fill; | ||
132 | struct sk_buff_head rx_list; | ||
133 | |||
134 | spinlock_t lock; | ||
135 | unsigned int last_duplex; | ||
136 | unsigned int last_link; | ||
137 | unsigned int last_speed; | ||
138 | struct device *dev; | ||
139 | struct napi_struct napi; | ||
140 | struct tasklet_struct tx_clean_tasklet; | ||
141 | struct phy_device *phydev; | ||
142 | struct device_node *phy_np; | ||
143 | resource_size_t mix_phys; | ||
144 | resource_size_t mix_size; | ||
145 | resource_size_t agl_phys; | ||
146 | resource_size_t agl_size; | ||
147 | resource_size_t agl_prt_ctl_phys; | ||
148 | resource_size_t agl_prt_ctl_size; | ||
149 | }; | ||
150 | |||
151 | static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable) | ||
152 | { | ||
153 | union cvmx_mixx_intena mix_intena; | ||
154 | unsigned long flags; | ||
155 | |||
156 | spin_lock_irqsave(&p->lock, flags); | ||
157 | mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); | ||
158 | mix_intena.s.ithena = enable ? 1 : 0; | ||
159 | cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); | ||
160 | spin_unlock_irqrestore(&p->lock, flags); | ||
161 | } | ||
162 | |||
163 | static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable) | ||
164 | { | ||
165 | union cvmx_mixx_intena mix_intena; | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&p->lock, flags); | ||
169 | mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); | ||
170 | mix_intena.s.othena = enable ? 1 : 0; | ||
171 | cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); | ||
172 | spin_unlock_irqrestore(&p->lock, flags); | ||
173 | } | ||
174 | |||
175 | static void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p) | ||
176 | { | ||
177 | octeon_mgmt_set_rx_irq(p, 1); | ||
178 | } | ||
179 | |||
180 | static void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p) | ||
181 | { | ||
182 | octeon_mgmt_set_rx_irq(p, 0); | ||
183 | } | ||
184 | |||
185 | static void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p) | ||
186 | { | ||
187 | octeon_mgmt_set_tx_irq(p, 1); | ||
188 | } | ||
189 | |||
190 | static void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p) | ||
191 | { | ||
192 | octeon_mgmt_set_tx_irq(p, 0); | ||
193 | } | ||
194 | |||
195 | static unsigned int ring_max_fill(unsigned int ring_size) | ||
196 | { | ||
197 | return ring_size - 8; | ||
198 | } | ||
199 | |||
200 | static unsigned int ring_size_to_bytes(unsigned int ring_size) | ||
201 | { | ||
202 | return ring_size * sizeof(union mgmt_port_ring_entry); | ||
203 | } | ||
204 | |||
205 | static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) | ||
206 | { | ||
207 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
208 | |||
209 | while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) { | ||
210 | unsigned int size; | ||
211 | union mgmt_port_ring_entry re; | ||
212 | struct sk_buff *skb; | ||
213 | |||
214 | /* CN56XX pass 1 needs 8 bytes of padding. */ | ||
215 | size = netdev->mtu + OCTEON_MGMT_RX_HEADROOM + 8 + NET_IP_ALIGN; | ||
216 | |||
217 | skb = netdev_alloc_skb(netdev, size); | ||
218 | if (!skb) | ||
219 | break; | ||
220 | skb_reserve(skb, NET_IP_ALIGN); | ||
221 | __skb_queue_tail(&p->rx_list, skb); | ||
222 | |||
223 | re.d64 = 0; | ||
224 | re.s.len = size; | ||
225 | re.s.addr = dma_map_single(p->dev, skb->data, | ||
226 | size, | ||
227 | DMA_FROM_DEVICE); | ||
228 | |||
229 | /* Put it in the ring. */ | ||
230 | p->rx_ring[p->rx_next_fill] = re.d64; | ||
231 | dma_sync_single_for_device(p->dev, p->rx_ring_handle, | ||
232 | ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
233 | DMA_BIDIRECTIONAL); | ||
234 | p->rx_next_fill = | ||
235 | (p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE; | ||
236 | p->rx_current_fill++; | ||
237 | /* Ring the bell. */ | ||
238 | cvmx_write_csr(p->mix + MIX_IRING2, 1); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static ktime_t ptp_to_ktime(u64 ptptime) | ||
243 | { | ||
244 | ktime_t ktimebase; | ||
245 | u64 ptpbase; | ||
246 | unsigned long flags; | ||
247 | |||
248 | local_irq_save(flags); | ||
249 | /* Fill the icache with the code */ | ||
250 | ktime_get_real(); | ||
251 | /* Flush all pending operations */ | ||
252 | mb(); | ||
253 | /* Read the time and PTP clock as close together as | ||
254 | * possible. It is important that this sequence take the same | ||
255 | * amount of time to reduce jitter | ||
256 | */ | ||
257 | ktimebase = ktime_get_real(); | ||
258 | ptpbase = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_HI); | ||
259 | local_irq_restore(flags); | ||
260 | |||
261 | return ktime_sub_ns(ktimebase, ptpbase - ptptime); | ||
262 | } | ||
263 | |||
264 | static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) | ||
265 | { | ||
266 | union cvmx_mixx_orcnt mix_orcnt; | ||
267 | union mgmt_port_ring_entry re; | ||
268 | struct sk_buff *skb; | ||
269 | int cleaned = 0; | ||
270 | unsigned long flags; | ||
271 | |||
272 | mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); | ||
273 | while (mix_orcnt.s.orcnt) { | ||
274 | spin_lock_irqsave(&p->tx_list.lock, flags); | ||
275 | |||
276 | mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); | ||
277 | |||
278 | if (mix_orcnt.s.orcnt == 0) { | ||
279 | spin_unlock_irqrestore(&p->tx_list.lock, flags); | ||
280 | break; | ||
281 | } | ||
282 | |||
283 | dma_sync_single_for_cpu(p->dev, p->tx_ring_handle, | ||
284 | ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
285 | DMA_BIDIRECTIONAL); | ||
286 | |||
287 | re.d64 = p->tx_ring[p->tx_next_clean]; | ||
288 | p->tx_next_clean = | ||
289 | (p->tx_next_clean + 1) % OCTEON_MGMT_TX_RING_SIZE; | ||
290 | skb = __skb_dequeue(&p->tx_list); | ||
291 | |||
292 | mix_orcnt.u64 = 0; | ||
293 | mix_orcnt.s.orcnt = 1; | ||
294 | |||
295 | /* Acknowledge to hardware that we have the buffer. */ | ||
296 | cvmx_write_csr(p->mix + MIX_ORCNT, mix_orcnt.u64); | ||
297 | p->tx_current_fill--; | ||
298 | |||
299 | spin_unlock_irqrestore(&p->tx_list.lock, flags); | ||
300 | |||
301 | dma_unmap_single(p->dev, re.s.addr, re.s.len, | ||
302 | DMA_TO_DEVICE); | ||
303 | |||
304 | /* Read the hardware TX timestamp if one was recorded */ | ||
305 | if (unlikely(re.s.tstamp)) { | ||
306 | struct skb_shared_hwtstamps ts; | ||
307 | /* Read the timestamp */ | ||
308 | u64 ns = cvmx_read_csr(CVMX_MIXX_TSTAMP(p->port)); | ||
309 | /* Remove the timestamp from the FIFO */ | ||
310 | cvmx_write_csr(CVMX_MIXX_TSCTL(p->port), 0); | ||
311 | /* Tell the kernel about the timestamp */ | ||
312 | ts.syststamp = ptp_to_ktime(ns); | ||
313 | ts.hwtstamp = ns_to_ktime(ns); | ||
314 | skb_tstamp_tx(skb, &ts); | ||
315 | } | ||
316 | |||
317 | dev_kfree_skb_any(skb); | ||
318 | cleaned++; | ||
319 | |||
320 | mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); | ||
321 | } | ||
322 | |||
323 | if (cleaned && netif_queue_stopped(p->netdev)) | ||
324 | netif_wake_queue(p->netdev); | ||
325 | } | ||
326 | |||
327 | static void octeon_mgmt_clean_tx_tasklet(unsigned long arg) | ||
328 | { | ||
329 | struct octeon_mgmt *p = (struct octeon_mgmt *)arg; | ||
330 | octeon_mgmt_clean_tx_buffers(p); | ||
331 | octeon_mgmt_enable_tx_irq(p); | ||
332 | } | ||
333 | |||
334 | static void octeon_mgmt_update_rx_stats(struct net_device *netdev) | ||
335 | { | ||
336 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
337 | unsigned long flags; | ||
338 | u64 drop, bad; | ||
339 | |||
340 | /* These reads also clear the count registers. */ | ||
341 | drop = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP); | ||
342 | bad = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD); | ||
343 | |||
344 | if (drop || bad) { | ||
345 | /* Do an atomic update. */ | ||
346 | spin_lock_irqsave(&p->lock, flags); | ||
347 | netdev->stats.rx_errors += bad; | ||
348 | netdev->stats.rx_dropped += drop; | ||
349 | spin_unlock_irqrestore(&p->lock, flags); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static void octeon_mgmt_update_tx_stats(struct net_device *netdev) | ||
354 | { | ||
355 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
356 | unsigned long flags; | ||
357 | |||
358 | union cvmx_agl_gmx_txx_stat0 s0; | ||
359 | union cvmx_agl_gmx_txx_stat1 s1; | ||
360 | |||
361 | /* These reads also clear the count registers. */ | ||
362 | s0.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT0); | ||
363 | s1.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT1); | ||
364 | |||
365 | if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) { | ||
366 | /* Do an atomic update. */ | ||
367 | spin_lock_irqsave(&p->lock, flags); | ||
368 | netdev->stats.tx_errors += s0.s.xsdef + s0.s.xscol; | ||
369 | netdev->stats.collisions += s1.s.scol + s1.s.mcol; | ||
370 | spin_unlock_irqrestore(&p->lock, flags); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Dequeue a receive skb and its corresponding ring entry. The ring | ||
376 | * entry is returned, *pskb is updated to point to the skb. | ||
377 | */ | ||
378 | static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p, | ||
379 | struct sk_buff **pskb) | ||
380 | { | ||
381 | union mgmt_port_ring_entry re; | ||
382 | |||
383 | dma_sync_single_for_cpu(p->dev, p->rx_ring_handle, | ||
384 | ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
385 | DMA_BIDIRECTIONAL); | ||
386 | |||
387 | re.d64 = p->rx_ring[p->rx_next]; | ||
388 | p->rx_next = (p->rx_next + 1) % OCTEON_MGMT_RX_RING_SIZE; | ||
389 | p->rx_current_fill--; | ||
390 | *pskb = __skb_dequeue(&p->rx_list); | ||
391 | |||
392 | dma_unmap_single(p->dev, re.s.addr, | ||
393 | ETH_FRAME_LEN + OCTEON_MGMT_RX_HEADROOM, | ||
394 | DMA_FROM_DEVICE); | ||
395 | |||
396 | return re.d64; | ||
397 | } | ||
398 | |||
399 | |||
400 | static int octeon_mgmt_receive_one(struct octeon_mgmt *p) | ||
401 | { | ||
402 | struct net_device *netdev = p->netdev; | ||
403 | union cvmx_mixx_ircnt mix_ircnt; | ||
404 | union mgmt_port_ring_entry re; | ||
405 | struct sk_buff *skb; | ||
406 | struct sk_buff *skb2; | ||
407 | struct sk_buff *skb_new; | ||
408 | union mgmt_port_ring_entry re2; | ||
409 | int rc = 1; | ||
410 | |||
411 | |||
412 | re.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb); | ||
413 | if (likely(re.s.code == RING_ENTRY_CODE_DONE)) { | ||
414 | /* A good packet, send it up. */ | ||
415 | skb_put(skb, re.s.len); | ||
416 | good: | ||
417 | /* Process the RX timestamp if it was recorded */ | ||
418 | if (p->has_rx_tstamp) { | ||
419 | /* The first 8 bytes are the timestamp */ | ||
420 | u64 ns = *(u64 *)skb->data; | ||
421 | struct skb_shared_hwtstamps *ts; | ||
422 | ts = skb_hwtstamps(skb); | ||
423 | ts->hwtstamp = ns_to_ktime(ns); | ||
424 | ts->syststamp = ptp_to_ktime(ns); | ||
425 | __skb_pull(skb, 8); | ||
426 | } | ||
427 | skb->protocol = eth_type_trans(skb, netdev); | ||
428 | netdev->stats.rx_packets++; | ||
429 | netdev->stats.rx_bytes += skb->len; | ||
430 | netif_receive_skb(skb); | ||
431 | rc = 0; | ||
432 | } else if (re.s.code == RING_ENTRY_CODE_MORE) { | ||
433 | /* Packet split across skbs. This can happen if we | ||
434 | * increase the MTU. Buffers that are already in the | ||
435 | * rx ring can then end up being too small. As the rx | ||
436 | * ring is refilled, buffers sized for the new MTU | ||
437 | * will be used and we should go back to the normal | ||
438 | * non-split case. | ||
439 | */ | ||
440 | skb_put(skb, re.s.len); | ||
441 | do { | ||
442 | re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2); | ||
443 | if (re2.s.code != RING_ENTRY_CODE_MORE | ||
444 | && re2.s.code != RING_ENTRY_CODE_DONE) | ||
445 | goto split_error; | ||
446 | skb_put(skb2, re2.s.len); | ||
447 | skb_new = skb_copy_expand(skb, 0, skb2->len, | ||
448 | GFP_ATOMIC); | ||
449 | if (!skb_new) | ||
450 | goto split_error; | ||
451 | if (skb_copy_bits(skb2, 0, skb_tail_pointer(skb_new), | ||
452 | skb2->len)) | ||
453 | goto split_error; | ||
454 | skb_put(skb_new, skb2->len); | ||
455 | dev_kfree_skb_any(skb); | ||
456 | dev_kfree_skb_any(skb2); | ||
457 | skb = skb_new; | ||
458 | } while (re2.s.code == RING_ENTRY_CODE_MORE); | ||
459 | goto good; | ||
460 | } else { | ||
461 | /* Some other error, discard it. */ | ||
462 | dev_kfree_skb_any(skb); | ||
463 | /* Error statistics are accumulated in | ||
464 | * octeon_mgmt_update_rx_stats. | ||
465 | */ | ||
466 | } | ||
467 | goto done; | ||
468 | split_error: | ||
469 | /* Discard the whole mess. */ | ||
470 | dev_kfree_skb_any(skb); | ||
471 | dev_kfree_skb_any(skb2); | ||
472 | while (re2.s.code == RING_ENTRY_CODE_MORE) { | ||
473 | re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2); | ||
474 | dev_kfree_skb_any(skb2); | ||
475 | } | ||
476 | netdev->stats.rx_errors++; | ||
477 | |||
478 | done: | ||
479 | /* Tell the hardware we processed a packet. */ | ||
480 | mix_ircnt.u64 = 0; | ||
481 | mix_ircnt.s.ircnt = 1; | ||
482 | cvmx_write_csr(p->mix + MIX_IRCNT, mix_ircnt.u64); | ||
483 | return rc; | ||
484 | } | ||
485 | |||
486 | static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget) | ||
487 | { | ||
488 | unsigned int work_done = 0; | ||
489 | union cvmx_mixx_ircnt mix_ircnt; | ||
490 | int rc; | ||
491 | |||
492 | mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT); | ||
493 | while (work_done < budget && mix_ircnt.s.ircnt) { | ||
494 | |||
495 | rc = octeon_mgmt_receive_one(p); | ||
496 | if (!rc) | ||
497 | work_done++; | ||
498 | |||
499 | /* Check for more packets. */ | ||
500 | mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT); | ||
501 | } | ||
502 | |||
503 | octeon_mgmt_rx_fill_ring(p->netdev); | ||
504 | |||
505 | return work_done; | ||
506 | } | ||
507 | |||
508 | static int octeon_mgmt_napi_poll(struct napi_struct *napi, int budget) | ||
509 | { | ||
510 | struct octeon_mgmt *p = container_of(napi, struct octeon_mgmt, napi); | ||
511 | struct net_device *netdev = p->netdev; | ||
512 | unsigned int work_done = 0; | ||
513 | |||
514 | work_done = octeon_mgmt_receive_packets(p, budget); | ||
515 | |||
516 | if (work_done < budget) { | ||
517 | /* We stopped because no more packets were available. */ | ||
518 | napi_complete(napi); | ||
519 | octeon_mgmt_enable_rx_irq(p); | ||
520 | } | ||
521 | octeon_mgmt_update_rx_stats(netdev); | ||
522 | |||
523 | return work_done; | ||
524 | } | ||
525 | |||
526 | /* Reset the hardware to clean state. */ | ||
527 | static void octeon_mgmt_reset_hw(struct octeon_mgmt *p) | ||
528 | { | ||
529 | union cvmx_mixx_ctl mix_ctl; | ||
530 | union cvmx_mixx_bist mix_bist; | ||
531 | union cvmx_agl_gmx_bist agl_gmx_bist; | ||
532 | |||
533 | mix_ctl.u64 = 0; | ||
534 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | ||
535 | do { | ||
536 | mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); | ||
537 | } while (mix_ctl.s.busy); | ||
538 | mix_ctl.s.reset = 1; | ||
539 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | ||
540 | cvmx_read_csr(p->mix + MIX_CTL); | ||
541 | octeon_io_clk_delay(64); | ||
542 | |||
543 | mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST); | ||
544 | if (mix_bist.u64) | ||
545 | dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n", | ||
546 | (unsigned long long)mix_bist.u64); | ||
547 | |||
548 | agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST); | ||
549 | if (agl_gmx_bist.u64) | ||
550 | dev_warn(p->dev, "AGL failed BIST (0x%016llx)\n", | ||
551 | (unsigned long long)agl_gmx_bist.u64); | ||
552 | } | ||
553 | |||
554 | struct octeon_mgmt_cam_state { | ||
555 | u64 cam[6]; | ||
556 | u64 cam_mask; | ||
557 | int cam_index; | ||
558 | }; | ||
559 | |||
560 | static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs, | ||
561 | unsigned char *addr) | ||
562 | { | ||
563 | int i; | ||
564 | |||
565 | for (i = 0; i < 6; i++) | ||
566 | cs->cam[i] |= (u64)addr[i] << (8 * (cs->cam_index)); | ||
567 | cs->cam_mask |= (1ULL << cs->cam_index); | ||
568 | cs->cam_index++; | ||
569 | } | ||
570 | |||
571 | static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) | ||
572 | { | ||
573 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
574 | union cvmx_agl_gmx_rxx_adr_ctl adr_ctl; | ||
575 | union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx; | ||
576 | unsigned long flags; | ||
577 | unsigned int prev_packet_enable; | ||
578 | unsigned int cam_mode = 1; /* 1 - Accept on CAM match */ | ||
579 | unsigned int multicast_mode = 1; /* 1 - Reject all multicast. */ | ||
580 | struct octeon_mgmt_cam_state cam_state; | ||
581 | struct netdev_hw_addr *ha; | ||
582 | int available_cam_entries; | ||
583 | |||
584 | memset(&cam_state, 0, sizeof(cam_state)); | ||
585 | |||
586 | if ((netdev->flags & IFF_PROMISC) || netdev->uc.count > 7) { | ||
587 | cam_mode = 0; | ||
588 | available_cam_entries = 8; | ||
589 | } else { | ||
590 | /* One CAM entry for the primary address, leaves seven | ||
591 | * for the secondary addresses. | ||
592 | */ | ||
593 | available_cam_entries = 7 - netdev->uc.count; | ||
594 | } | ||
595 | |||
596 | if (netdev->flags & IFF_MULTICAST) { | ||
597 | if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) || | ||
598 | netdev_mc_count(netdev) > available_cam_entries) | ||
599 | multicast_mode = 2; /* 2 - Accept all multicast. */ | ||
600 | else | ||
601 | multicast_mode = 0; /* 0 - Use CAM. */ | ||
602 | } | ||
603 | |||
604 | if (cam_mode == 1) { | ||
605 | /* Add primary address. */ | ||
606 | octeon_mgmt_cam_state_add(&cam_state, netdev->dev_addr); | ||
607 | netdev_for_each_uc_addr(ha, netdev) | ||
608 | octeon_mgmt_cam_state_add(&cam_state, ha->addr); | ||
609 | } | ||
610 | if (multicast_mode == 0) { | ||
611 | netdev_for_each_mc_addr(ha, netdev) | ||
612 | octeon_mgmt_cam_state_add(&cam_state, ha->addr); | ||
613 | } | ||
614 | |||
615 | spin_lock_irqsave(&p->lock, flags); | ||
616 | |||
617 | /* Disable packet I/O. */ | ||
618 | agl_gmx_prtx.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
619 | prev_packet_enable = agl_gmx_prtx.s.en; | ||
620 | agl_gmx_prtx.s.en = 0; | ||
621 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64); | ||
622 | |||
623 | adr_ctl.u64 = 0; | ||
624 | adr_ctl.s.cam_mode = cam_mode; | ||
625 | adr_ctl.s.mcst = multicast_mode; | ||
626 | adr_ctl.s.bcst = 1; /* Allow broadcast */ | ||
627 | |||
628 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CTL, adr_ctl.u64); | ||
629 | |||
630 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM0, cam_state.cam[0]); | ||
631 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM1, cam_state.cam[1]); | ||
632 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM2, cam_state.cam[2]); | ||
633 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM3, cam_state.cam[3]); | ||
634 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM4, cam_state.cam[4]); | ||
635 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM5, cam_state.cam[5]); | ||
636 | cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM_EN, cam_state.cam_mask); | ||
637 | |||
638 | /* Restore packet I/O. */ | ||
639 | agl_gmx_prtx.s.en = prev_packet_enable; | ||
640 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64); | ||
641 | |||
642 | spin_unlock_irqrestore(&p->lock, flags); | ||
643 | } | ||
644 | |||
645 | static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr) | ||
646 | { | ||
647 | int r = eth_mac_addr(netdev, addr); | ||
648 | |||
649 | if (r) | ||
650 | return r; | ||
651 | |||
652 | octeon_mgmt_set_rx_filtering(netdev); | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu) | ||
658 | { | ||
659 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
660 | int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM; | ||
661 | |||
662 | /* Limit the MTU to make sure the ethernet packets are between | ||
663 | * 64 bytes and 16383 bytes. | ||
664 | */ | ||
665 | if (size_without_fcs < 64 || size_without_fcs > 16383) { | ||
666 | dev_warn(p->dev, "MTU must be between %d and %d.\n", | ||
667 | 64 - OCTEON_MGMT_RX_HEADROOM, | ||
668 | 16383 - OCTEON_MGMT_RX_HEADROOM); | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | netdev->mtu = new_mtu; | ||
673 | |||
674 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, size_without_fcs); | ||
675 | cvmx_write_csr(p->agl + AGL_GMX_RX_JABBER, | ||
676 | (size_without_fcs + 7) & 0xfff8); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id) | ||
682 | { | ||
683 | struct net_device *netdev = dev_id; | ||
684 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
685 | union cvmx_mixx_isr mixx_isr; | ||
686 | |||
687 | mixx_isr.u64 = cvmx_read_csr(p->mix + MIX_ISR); | ||
688 | |||
689 | /* Clear any pending interrupts */ | ||
690 | cvmx_write_csr(p->mix + MIX_ISR, mixx_isr.u64); | ||
691 | cvmx_read_csr(p->mix + MIX_ISR); | ||
692 | |||
693 | if (mixx_isr.s.irthresh) { | ||
694 | octeon_mgmt_disable_rx_irq(p); | ||
695 | napi_schedule(&p->napi); | ||
696 | } | ||
697 | if (mixx_isr.s.orthresh) { | ||
698 | octeon_mgmt_disable_tx_irq(p); | ||
699 | tasklet_schedule(&p->tx_clean_tasklet); | ||
700 | } | ||
701 | |||
702 | return IRQ_HANDLED; | ||
703 | } | ||
704 | |||
705 | static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev, | ||
706 | struct ifreq *rq, int cmd) | ||
707 | { | ||
708 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
709 | struct hwtstamp_config config; | ||
710 | union cvmx_mio_ptp_clock_cfg ptp; | ||
711 | union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl; | ||
712 | bool have_hw_timestamps = false; | ||
713 | |||
714 | if (copy_from_user(&config, rq->ifr_data, sizeof(config))) | ||
715 | return -EFAULT; | ||
716 | |||
717 | if (config.flags) /* reserved for future extensions */ | ||
718 | return -EINVAL; | ||
719 | |||
720 | /* Check the status of hardware for tiemstamps */ | ||
721 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
722 | /* Get the current state of the PTP clock */ | ||
723 | ptp.u64 = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_CFG); | ||
724 | if (!ptp.s.ext_clk_en) { | ||
725 | /* The clock has not been configured to use an | ||
726 | * external source. Program it to use the main clock | ||
727 | * reference. | ||
728 | */ | ||
729 | u64 clock_comp = (NSEC_PER_SEC << 32) / octeon_get_io_clock_rate(); | ||
730 | if (!ptp.s.ptp_en) | ||
731 | cvmx_write_csr(CVMX_MIO_PTP_CLOCK_COMP, clock_comp); | ||
732 | pr_info("PTP Clock: Using sclk reference at %lld Hz\n", | ||
733 | (NSEC_PER_SEC << 32) / clock_comp); | ||
734 | } else { | ||
735 | /* The clock is already programmed to use a GPIO */ | ||
736 | u64 clock_comp = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_COMP); | ||
737 | pr_info("PTP Clock: Using GPIO %d at %lld Hz\n", | ||
738 | ptp.s.ext_clk_in, | ||
739 | (NSEC_PER_SEC << 32) / clock_comp); | ||
740 | } | ||
741 | |||
742 | /* Enable the clock if it wasn't done already */ | ||
743 | if (!ptp.s.ptp_en) { | ||
744 | ptp.s.ptp_en = 1; | ||
745 | cvmx_write_csr(CVMX_MIO_PTP_CLOCK_CFG, ptp.u64); | ||
746 | } | ||
747 | have_hw_timestamps = true; | ||
748 | } | ||
749 | |||
750 | if (!have_hw_timestamps) | ||
751 | return -EINVAL; | ||
752 | |||
753 | switch (config.tx_type) { | ||
754 | case HWTSTAMP_TX_OFF: | ||
755 | case HWTSTAMP_TX_ON: | ||
756 | break; | ||
757 | default: | ||
758 | return -ERANGE; | ||
759 | } | ||
760 | |||
761 | switch (config.rx_filter) { | ||
762 | case HWTSTAMP_FILTER_NONE: | ||
763 | p->has_rx_tstamp = false; | ||
764 | rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL); | ||
765 | rxx_frm_ctl.s.ptp_mode = 0; | ||
766 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | ||
767 | break; | ||
768 | case HWTSTAMP_FILTER_ALL: | ||
769 | case HWTSTAMP_FILTER_SOME: | ||
770 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
771 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
772 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
773 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
774 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
775 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
776 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
777 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
778 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
779 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
780 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
781 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
782 | p->has_rx_tstamp = have_hw_timestamps; | ||
783 | config.rx_filter = HWTSTAMP_FILTER_ALL; | ||
784 | if (p->has_rx_tstamp) { | ||
785 | rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL); | ||
786 | rxx_frm_ctl.s.ptp_mode = 1; | ||
787 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | ||
788 | } | ||
789 | break; | ||
790 | default: | ||
791 | return -ERANGE; | ||
792 | } | ||
793 | |||
794 | if (copy_to_user(rq->ifr_data, &config, sizeof(config))) | ||
795 | return -EFAULT; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int octeon_mgmt_ioctl(struct net_device *netdev, | ||
801 | struct ifreq *rq, int cmd) | ||
802 | { | ||
803 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
804 | |||
805 | switch (cmd) { | ||
806 | case SIOCSHWTSTAMP: | ||
807 | return octeon_mgmt_ioctl_hwtstamp(netdev, rq, cmd); | ||
808 | default: | ||
809 | if (p->phydev) | ||
810 | return phy_mii_ioctl(p->phydev, rq, cmd); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | static void octeon_mgmt_disable_link(struct octeon_mgmt *p) | ||
816 | { | ||
817 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
818 | |||
819 | /* Disable GMX before we make any changes. */ | ||
820 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
821 | prtx_cfg.s.en = 0; | ||
822 | prtx_cfg.s.tx_en = 0; | ||
823 | prtx_cfg.s.rx_en = 0; | ||
824 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
825 | |||
826 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
827 | int i; | ||
828 | for (i = 0; i < 10; i++) { | ||
829 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
830 | if (prtx_cfg.s.tx_idle == 1 || prtx_cfg.s.rx_idle == 1) | ||
831 | break; | ||
832 | mdelay(1); | ||
833 | i++; | ||
834 | } | ||
835 | } | ||
836 | } | ||
837 | |||
838 | static void octeon_mgmt_enable_link(struct octeon_mgmt *p) | ||
839 | { | ||
840 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
841 | |||
842 | /* Restore the GMX enable state only if link is set */ | ||
843 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
844 | prtx_cfg.s.tx_en = 1; | ||
845 | prtx_cfg.s.rx_en = 1; | ||
846 | prtx_cfg.s.en = 1; | ||
847 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
848 | } | ||
849 | |||
850 | static void octeon_mgmt_update_link(struct octeon_mgmt *p) | ||
851 | { | ||
852 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
853 | |||
854 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
855 | |||
856 | if (!p->phydev->link) | ||
857 | prtx_cfg.s.duplex = 1; | ||
858 | else | ||
859 | prtx_cfg.s.duplex = p->phydev->duplex; | ||
860 | |||
861 | switch (p->phydev->speed) { | ||
862 | case 10: | ||
863 | prtx_cfg.s.speed = 0; | ||
864 | prtx_cfg.s.slottime = 0; | ||
865 | |||
866 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
867 | prtx_cfg.s.burst = 1; | ||
868 | prtx_cfg.s.speed_msb = 1; | ||
869 | } | ||
870 | break; | ||
871 | case 100: | ||
872 | prtx_cfg.s.speed = 0; | ||
873 | prtx_cfg.s.slottime = 0; | ||
874 | |||
875 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
876 | prtx_cfg.s.burst = 1; | ||
877 | prtx_cfg.s.speed_msb = 0; | ||
878 | } | ||
879 | break; | ||
880 | case 1000: | ||
881 | /* 1000 MBits is only supported on 6XXX chips */ | ||
882 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
883 | prtx_cfg.s.speed = 1; | ||
884 | prtx_cfg.s.speed_msb = 0; | ||
885 | /* Only matters for half-duplex */ | ||
886 | prtx_cfg.s.slottime = 1; | ||
887 | prtx_cfg.s.burst = p->phydev->duplex; | ||
888 | } | ||
889 | break; | ||
890 | case 0: /* No link */ | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | /* Write the new GMX setting with the port still disabled. */ | ||
896 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
897 | |||
898 | /* Read GMX CFG again to make sure the config is completed. */ | ||
899 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
900 | |||
901 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
902 | union cvmx_agl_gmx_txx_clk agl_clk; | ||
903 | union cvmx_agl_prtx_ctl prtx_ctl; | ||
904 | |||
905 | prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
906 | agl_clk.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_CLK); | ||
907 | /* MII (both speeds) and RGMII 1000 speed. */ | ||
908 | agl_clk.s.clk_cnt = 1; | ||
909 | if (prtx_ctl.s.mode == 0) { /* RGMII mode */ | ||
910 | if (p->phydev->speed == 10) | ||
911 | agl_clk.s.clk_cnt = 50; | ||
912 | else if (p->phydev->speed == 100) | ||
913 | agl_clk.s.clk_cnt = 5; | ||
914 | } | ||
915 | cvmx_write_csr(p->agl + AGL_GMX_TX_CLK, agl_clk.u64); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | static void octeon_mgmt_adjust_link(struct net_device *netdev) | ||
920 | { | ||
921 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
922 | unsigned long flags; | ||
923 | int link_changed = 0; | ||
924 | |||
925 | if (!p->phydev) | ||
926 | return; | ||
927 | |||
928 | spin_lock_irqsave(&p->lock, flags); | ||
929 | |||
930 | |||
931 | if (!p->phydev->link && p->last_link) | ||
932 | link_changed = -1; | ||
933 | |||
934 | if (p->phydev->link | ||
935 | && (p->last_duplex != p->phydev->duplex | ||
936 | || p->last_link != p->phydev->link | ||
937 | || p->last_speed != p->phydev->speed)) { | ||
938 | octeon_mgmt_disable_link(p); | ||
939 | link_changed = 1; | ||
940 | octeon_mgmt_update_link(p); | ||
941 | octeon_mgmt_enable_link(p); | ||
942 | } | ||
943 | |||
944 | p->last_link = p->phydev->link; | ||
945 | p->last_speed = p->phydev->speed; | ||
946 | p->last_duplex = p->phydev->duplex; | ||
947 | |||
948 | spin_unlock_irqrestore(&p->lock, flags); | ||
949 | |||
950 | if (link_changed != 0) { | ||
951 | if (link_changed > 0) { | ||
952 | pr_info("%s: Link is up - %d/%s\n", netdev->name, | ||
953 | p->phydev->speed, | ||
954 | DUPLEX_FULL == p->phydev->duplex ? | ||
955 | "Full" : "Half"); | ||
956 | } else { | ||
957 | pr_info("%s: Link is down\n", netdev->name); | ||
958 | } | ||
959 | } | ||
960 | } | ||
961 | |||
962 | static int octeon_mgmt_init_phy(struct net_device *netdev) | ||
963 | { | ||
964 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
965 | |||
966 | if (octeon_is_simulation() || p->phy_np == NULL) { | ||
967 | /* No PHYs in the simulator. */ | ||
968 | netif_carrier_on(netdev); | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | p->phydev = of_phy_connect(netdev, p->phy_np, | ||
973 | octeon_mgmt_adjust_link, 0, | ||
974 | PHY_INTERFACE_MODE_MII); | ||
975 | |||
976 | if (!p->phydev) | ||
977 | return -ENODEV; | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int octeon_mgmt_open(struct net_device *netdev) | ||
983 | { | ||
984 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
985 | union cvmx_mixx_ctl mix_ctl; | ||
986 | union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode; | ||
987 | union cvmx_mixx_oring1 oring1; | ||
988 | union cvmx_mixx_iring1 iring1; | ||
989 | union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl; | ||
990 | union cvmx_mixx_irhwm mix_irhwm; | ||
991 | union cvmx_mixx_orhwm mix_orhwm; | ||
992 | union cvmx_mixx_intena mix_intena; | ||
993 | struct sockaddr sa; | ||
994 | |||
995 | /* Allocate ring buffers. */ | ||
996 | p->tx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
997 | GFP_KERNEL); | ||
998 | if (!p->tx_ring) | ||
999 | return -ENOMEM; | ||
1000 | p->tx_ring_handle = | ||
1001 | dma_map_single(p->dev, p->tx_ring, | ||
1002 | ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
1003 | DMA_BIDIRECTIONAL); | ||
1004 | p->tx_next = 0; | ||
1005 | p->tx_next_clean = 0; | ||
1006 | p->tx_current_fill = 0; | ||
1007 | |||
1008 | |||
1009 | p->rx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
1010 | GFP_KERNEL); | ||
1011 | if (!p->rx_ring) | ||
1012 | goto err_nomem; | ||
1013 | p->rx_ring_handle = | ||
1014 | dma_map_single(p->dev, p->rx_ring, | ||
1015 | ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
1016 | DMA_BIDIRECTIONAL); | ||
1017 | |||
1018 | p->rx_next = 0; | ||
1019 | p->rx_next_fill = 0; | ||
1020 | p->rx_current_fill = 0; | ||
1021 | |||
1022 | octeon_mgmt_reset_hw(p); | ||
1023 | |||
1024 | mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); | ||
1025 | |||
1026 | /* Bring it out of reset if needed. */ | ||
1027 | if (mix_ctl.s.reset) { | ||
1028 | mix_ctl.s.reset = 0; | ||
1029 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | ||
1030 | do { | ||
1031 | mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); | ||
1032 | } while (mix_ctl.s.reset); | ||
1033 | } | ||
1034 | |||
1035 | if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { | ||
1036 | agl_gmx_inf_mode.u64 = 0; | ||
1037 | agl_gmx_inf_mode.s.en = 1; | ||
1038 | cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); | ||
1039 | } | ||
1040 | if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) | ||
1041 | || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { | ||
1042 | /* Force compensation values, as they are not | ||
1043 | * determined properly by HW | ||
1044 | */ | ||
1045 | union cvmx_agl_gmx_drv_ctl drv_ctl; | ||
1046 | |||
1047 | drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL); | ||
1048 | if (p->port) { | ||
1049 | drv_ctl.s.byp_en1 = 1; | ||
1050 | drv_ctl.s.nctl1 = 6; | ||
1051 | drv_ctl.s.pctl1 = 6; | ||
1052 | } else { | ||
1053 | drv_ctl.s.byp_en = 1; | ||
1054 | drv_ctl.s.nctl = 6; | ||
1055 | drv_ctl.s.pctl = 6; | ||
1056 | } | ||
1057 | cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64); | ||
1058 | } | ||
1059 | |||
1060 | oring1.u64 = 0; | ||
1061 | oring1.s.obase = p->tx_ring_handle >> 3; | ||
1062 | oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE; | ||
1063 | cvmx_write_csr(p->mix + MIX_ORING1, oring1.u64); | ||
1064 | |||
1065 | iring1.u64 = 0; | ||
1066 | iring1.s.ibase = p->rx_ring_handle >> 3; | ||
1067 | iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE; | ||
1068 | cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64); | ||
1069 | |||
1070 | memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN); | ||
1071 | octeon_mgmt_set_mac_address(netdev, &sa); | ||
1072 | |||
1073 | octeon_mgmt_change_mtu(netdev, netdev->mtu); | ||
1074 | |||
1075 | /* Enable the port HW. Packets are not allowed until | ||
1076 | * cvmx_mgmt_port_enable() is called. | ||
1077 | */ | ||
1078 | mix_ctl.u64 = 0; | ||
1079 | mix_ctl.s.crc_strip = 1; /* Strip the ending CRC */ | ||
1080 | mix_ctl.s.en = 1; /* Enable the port */ | ||
1081 | mix_ctl.s.nbtarb = 0; /* Arbitration mode */ | ||
1082 | /* MII CB-request FIFO programmable high watermark */ | ||
1083 | mix_ctl.s.mrq_hwm = 1; | ||
1084 | #ifdef __LITTLE_ENDIAN | ||
1085 | mix_ctl.s.lendian = 1; | ||
1086 | #endif | ||
1087 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | ||
1088 | |||
1089 | /* Read the PHY to find the mode of the interface. */ | ||
1090 | if (octeon_mgmt_init_phy(netdev)) { | ||
1091 | dev_err(p->dev, "Cannot initialize PHY on MIX%d.\n", p->port); | ||
1092 | goto err_noirq; | ||
1093 | } | ||
1094 | |||
1095 | /* Set the mode of the interface, RGMII/MII. */ | ||
1096 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && p->phydev) { | ||
1097 | union cvmx_agl_prtx_ctl agl_prtx_ctl; | ||
1098 | int rgmii_mode = (p->phydev->supported & | ||
1099 | (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) != 0; | ||
1100 | |||
1101 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
1102 | agl_prtx_ctl.s.mode = rgmii_mode ? 0 : 1; | ||
1103 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
1104 | |||
1105 | /* MII clocks counts are based on the 125Mhz | ||
1106 | * reference, which has an 8nS period. So our delays | ||
1107 | * need to be multiplied by this factor. | ||
1108 | */ | ||
1109 | #define NS_PER_PHY_CLK 8 | ||
1110 | |||
1111 | /* Take the DLL and clock tree out of reset */ | ||
1112 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
1113 | agl_prtx_ctl.s.clkrst = 0; | ||
1114 | if (rgmii_mode) { | ||
1115 | agl_prtx_ctl.s.dllrst = 0; | ||
1116 | agl_prtx_ctl.s.clktx_byp = 0; | ||
1117 | } | ||
1118 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
1119 | cvmx_read_csr(p->agl_prt_ctl); /* Force write out before wait */ | ||
1120 | |||
1121 | /* Wait for the DLL to lock. External 125 MHz | ||
1122 | * reference clock must be stable at this point. | ||
1123 | */ | ||
1124 | ndelay(256 * NS_PER_PHY_CLK); | ||
1125 | |||
1126 | /* Enable the interface */ | ||
1127 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
1128 | agl_prtx_ctl.s.enable = 1; | ||
1129 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
1130 | |||
1131 | /* Read the value back to force the previous write */ | ||
1132 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
1133 | |||
1134 | /* Enable the compensation controller */ | ||
1135 | agl_prtx_ctl.s.comp = 1; | ||
1136 | agl_prtx_ctl.s.drv_byp = 0; | ||
1137 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
1138 | /* Force write out before wait. */ | ||
1139 | cvmx_read_csr(p->agl_prt_ctl); | ||
1140 | |||
1141 | /* For compensation state to lock. */ | ||
1142 | ndelay(1040 * NS_PER_PHY_CLK); | ||
1143 | |||
1144 | /* Some Ethernet switches cannot handle standard | ||
1145 | * Interframe Gap, increase to 16 bytes. | ||
1146 | */ | ||
1147 | cvmx_write_csr(CVMX_AGL_GMX_TX_IFG, 0x88); | ||
1148 | } | ||
1149 | |||
1150 | octeon_mgmt_rx_fill_ring(netdev); | ||
1151 | |||
1152 | /* Clear statistics. */ | ||
1153 | /* Clear on read. */ | ||
1154 | cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_CTL, 1); | ||
1155 | cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP, 0); | ||
1156 | cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD, 0); | ||
1157 | |||
1158 | cvmx_write_csr(p->agl + AGL_GMX_TX_STATS_CTL, 1); | ||
1159 | cvmx_write_csr(p->agl + AGL_GMX_TX_STAT0, 0); | ||
1160 | cvmx_write_csr(p->agl + AGL_GMX_TX_STAT1, 0); | ||
1161 | |||
1162 | /* Clear any pending interrupts */ | ||
1163 | cvmx_write_csr(p->mix + MIX_ISR, cvmx_read_csr(p->mix + MIX_ISR)); | ||
1164 | |||
1165 | if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name, | ||
1166 | netdev)) { | ||
1167 | dev_err(p->dev, "request_irq(%d) failed.\n", p->irq); | ||
1168 | goto err_noirq; | ||
1169 | } | ||
1170 | |||
1171 | /* Interrupt every single RX packet */ | ||
1172 | mix_irhwm.u64 = 0; | ||
1173 | mix_irhwm.s.irhwm = 0; | ||
1174 | cvmx_write_csr(p->mix + MIX_IRHWM, mix_irhwm.u64); | ||
1175 | |||
1176 | /* Interrupt when we have 1 or more packets to clean. */ | ||
1177 | mix_orhwm.u64 = 0; | ||
1178 | mix_orhwm.s.orhwm = 0; | ||
1179 | cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64); | ||
1180 | |||
1181 | /* Enable receive and transmit interrupts */ | ||
1182 | mix_intena.u64 = 0; | ||
1183 | mix_intena.s.ithena = 1; | ||
1184 | mix_intena.s.othena = 1; | ||
1185 | cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); | ||
1186 | |||
1187 | /* Enable packet I/O. */ | ||
1188 | |||
1189 | rxx_frm_ctl.u64 = 0; | ||
1190 | rxx_frm_ctl.s.ptp_mode = p->has_rx_tstamp ? 1 : 0; | ||
1191 | rxx_frm_ctl.s.pre_align = 1; | ||
1192 | /* When set, disables the length check for non-min sized pkts | ||
1193 | * with padding in the client data. | ||
1194 | */ | ||
1195 | rxx_frm_ctl.s.pad_len = 1; | ||
1196 | /* When set, disables the length check for VLAN pkts */ | ||
1197 | rxx_frm_ctl.s.vlan_len = 1; | ||
1198 | /* When set, PREAMBLE checking is less strict */ | ||
1199 | rxx_frm_ctl.s.pre_free = 1; | ||
1200 | /* Control Pause Frames can match station SMAC */ | ||
1201 | rxx_frm_ctl.s.ctl_smac = 0; | ||
1202 | /* Control Pause Frames can match globally assign Multicast address */ | ||
1203 | rxx_frm_ctl.s.ctl_mcst = 1; | ||
1204 | /* Forward pause information to TX block */ | ||
1205 | rxx_frm_ctl.s.ctl_bck = 1; | ||
1206 | /* Drop Control Pause Frames */ | ||
1207 | rxx_frm_ctl.s.ctl_drp = 1; | ||
1208 | /* Strip off the preamble */ | ||
1209 | rxx_frm_ctl.s.pre_strp = 1; | ||
1210 | /* This port is configured to send PREAMBLE+SFD to begin every | ||
1211 | * frame. GMX checks that the PREAMBLE is sent correctly. | ||
1212 | */ | ||
1213 | rxx_frm_ctl.s.pre_chk = 1; | ||
1214 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | ||
1215 | |||
1216 | /* Configure the port duplex, speed and enables */ | ||
1217 | octeon_mgmt_disable_link(p); | ||
1218 | if (p->phydev) | ||
1219 | octeon_mgmt_update_link(p); | ||
1220 | octeon_mgmt_enable_link(p); | ||
1221 | |||
1222 | p->last_link = 0; | ||
1223 | p->last_speed = 0; | ||
1224 | /* PHY is not present in simulator. The carrier is enabled | ||
1225 | * while initializing the phy for simulator, leave it enabled. | ||
1226 | */ | ||
1227 | if (p->phydev) { | ||
1228 | netif_carrier_off(netdev); | ||
1229 | phy_start_aneg(p->phydev); | ||
1230 | } | ||
1231 | |||
1232 | netif_wake_queue(netdev); | ||
1233 | napi_enable(&p->napi); | ||
1234 | |||
1235 | return 0; | ||
1236 | err_noirq: | ||
1237 | octeon_mgmt_reset_hw(p); | ||
1238 | dma_unmap_single(p->dev, p->rx_ring_handle, | ||
1239 | ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
1240 | DMA_BIDIRECTIONAL); | ||
1241 | kfree(p->rx_ring); | ||
1242 | err_nomem: | ||
1243 | dma_unmap_single(p->dev, p->tx_ring_handle, | ||
1244 | ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
1245 | DMA_BIDIRECTIONAL); | ||
1246 | kfree(p->tx_ring); | ||
1247 | return -ENOMEM; | ||
1248 | } | ||
1249 | |||
1250 | static int octeon_mgmt_stop(struct net_device *netdev) | ||
1251 | { | ||
1252 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
1253 | |||
1254 | napi_disable(&p->napi); | ||
1255 | netif_stop_queue(netdev); | ||
1256 | |||
1257 | if (p->phydev) | ||
1258 | phy_disconnect(p->phydev); | ||
1259 | p->phydev = NULL; | ||
1260 | |||
1261 | netif_carrier_off(netdev); | ||
1262 | |||
1263 | octeon_mgmt_reset_hw(p); | ||
1264 | |||
1265 | free_irq(p->irq, netdev); | ||
1266 | |||
1267 | /* dma_unmap is a nop on Octeon, so just free everything. */ | ||
1268 | skb_queue_purge(&p->tx_list); | ||
1269 | skb_queue_purge(&p->rx_list); | ||
1270 | |||
1271 | dma_unmap_single(p->dev, p->rx_ring_handle, | ||
1272 | ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE), | ||
1273 | DMA_BIDIRECTIONAL); | ||
1274 | kfree(p->rx_ring); | ||
1275 | |||
1276 | dma_unmap_single(p->dev, p->tx_ring_handle, | ||
1277 | ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
1278 | DMA_BIDIRECTIONAL); | ||
1279 | kfree(p->tx_ring); | ||
1280 | |||
1281 | return 0; | ||
1282 | } | ||
1283 | |||
1284 | static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
1285 | { | ||
1286 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
1287 | union mgmt_port_ring_entry re; | ||
1288 | unsigned long flags; | ||
1289 | int rv = NETDEV_TX_BUSY; | ||
1290 | |||
1291 | re.d64 = 0; | ||
1292 | re.s.tstamp = ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) != 0); | ||
1293 | re.s.len = skb->len; | ||
1294 | re.s.addr = dma_map_single(p->dev, skb->data, | ||
1295 | skb->len, | ||
1296 | DMA_TO_DEVICE); | ||
1297 | |||
1298 | spin_lock_irqsave(&p->tx_list.lock, flags); | ||
1299 | |||
1300 | if (unlikely(p->tx_current_fill >= ring_max_fill(OCTEON_MGMT_TX_RING_SIZE) - 1)) { | ||
1301 | spin_unlock_irqrestore(&p->tx_list.lock, flags); | ||
1302 | netif_stop_queue(netdev); | ||
1303 | spin_lock_irqsave(&p->tx_list.lock, flags); | ||
1304 | } | ||
1305 | |||
1306 | if (unlikely(p->tx_current_fill >= | ||
1307 | ring_max_fill(OCTEON_MGMT_TX_RING_SIZE))) { | ||
1308 | spin_unlock_irqrestore(&p->tx_list.lock, flags); | ||
1309 | dma_unmap_single(p->dev, re.s.addr, re.s.len, | ||
1310 | DMA_TO_DEVICE); | ||
1311 | goto out; | ||
1312 | } | ||
1313 | |||
1314 | __skb_queue_tail(&p->tx_list, skb); | ||
1315 | |||
1316 | /* Put it in the ring. */ | ||
1317 | p->tx_ring[p->tx_next] = re.d64; | ||
1318 | p->tx_next = (p->tx_next + 1) % OCTEON_MGMT_TX_RING_SIZE; | ||
1319 | p->tx_current_fill++; | ||
1320 | |||
1321 | spin_unlock_irqrestore(&p->tx_list.lock, flags); | ||
1322 | |||
1323 | dma_sync_single_for_device(p->dev, p->tx_ring_handle, | ||
1324 | ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE), | ||
1325 | DMA_BIDIRECTIONAL); | ||
1326 | |||
1327 | netdev->stats.tx_packets++; | ||
1328 | netdev->stats.tx_bytes += skb->len; | ||
1329 | |||
1330 | /* Ring the bell. */ | ||
1331 | cvmx_write_csr(p->mix + MIX_ORING2, 1); | ||
1332 | |||
1333 | netdev->trans_start = jiffies; | ||
1334 | rv = NETDEV_TX_OK; | ||
1335 | out: | ||
1336 | octeon_mgmt_update_tx_stats(netdev); | ||
1337 | return rv; | ||
1338 | } | ||
1339 | |||
1340 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1341 | static void octeon_mgmt_poll_controller(struct net_device *netdev) | ||
1342 | { | ||
1343 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
1344 | |||
1345 | octeon_mgmt_receive_packets(p, 16); | ||
1346 | octeon_mgmt_update_rx_stats(netdev); | ||
1347 | } | ||
1348 | #endif | ||
1349 | |||
1350 | static void octeon_mgmt_get_drvinfo(struct net_device *netdev, | ||
1351 | struct ethtool_drvinfo *info) | ||
1352 | { | ||
1353 | strncpy(info->driver, DRV_NAME, sizeof(info->driver)); | ||
1354 | strncpy(info->version, DRV_VERSION, sizeof(info->version)); | ||
1355 | strncpy(info->fw_version, "N/A", sizeof(info->fw_version)); | ||
1356 | strncpy(info->bus_info, "N/A", sizeof(info->bus_info)); | ||
1357 | info->n_stats = 0; | ||
1358 | info->testinfo_len = 0; | ||
1359 | info->regdump_len = 0; | ||
1360 | info->eedump_len = 0; | ||
1361 | } | ||
1362 | |||
1363 | static int octeon_mgmt_get_settings(struct net_device *netdev, | ||
1364 | struct ethtool_cmd *cmd) | ||
1365 | { | ||
1366 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
1367 | |||
1368 | if (p->phydev) | ||
1369 | return phy_ethtool_gset(p->phydev, cmd); | ||
1370 | |||
1371 | return -EOPNOTSUPP; | ||
1372 | } | ||
1373 | |||
1374 | static int octeon_mgmt_set_settings(struct net_device *netdev, | ||
1375 | struct ethtool_cmd *cmd) | ||
1376 | { | ||
1377 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
1378 | |||
1379 | if (!capable(CAP_NET_ADMIN)) | ||
1380 | return -EPERM; | ||
1381 | |||
1382 | if (p->phydev) | ||
1383 | return phy_ethtool_sset(p->phydev, cmd); | ||
1384 | |||
1385 | return -EOPNOTSUPP; | ||
1386 | } | ||
1387 | |||
1388 | static int octeon_mgmt_nway_reset(struct net_device *dev) | ||
1389 | { | ||
1390 | struct octeon_mgmt *p = netdev_priv(dev); | ||
1391 | |||
1392 | if (!capable(CAP_NET_ADMIN)) | ||
1393 | return -EPERM; | ||
1394 | |||
1395 | if (p->phydev) | ||
1396 | return phy_start_aneg(p->phydev); | ||
1397 | |||
1398 | return -EOPNOTSUPP; | ||
1399 | } | ||
1400 | |||
1401 | static const struct ethtool_ops octeon_mgmt_ethtool_ops = { | ||
1402 | .get_drvinfo = octeon_mgmt_get_drvinfo, | ||
1403 | .get_settings = octeon_mgmt_get_settings, | ||
1404 | .set_settings = octeon_mgmt_set_settings, | ||
1405 | .nway_reset = octeon_mgmt_nway_reset, | ||
1406 | .get_link = ethtool_op_get_link, | ||
1407 | }; | ||
1408 | |||
1409 | static const struct net_device_ops octeon_mgmt_ops = { | ||
1410 | .ndo_open = octeon_mgmt_open, | ||
1411 | .ndo_stop = octeon_mgmt_stop, | ||
1412 | .ndo_start_xmit = octeon_mgmt_xmit, | ||
1413 | .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering, | ||
1414 | .ndo_set_mac_address = octeon_mgmt_set_mac_address, | ||
1415 | .ndo_do_ioctl = octeon_mgmt_ioctl, | ||
1416 | .ndo_change_mtu = octeon_mgmt_change_mtu, | ||
1417 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1418 | .ndo_poll_controller = octeon_mgmt_poll_controller, | ||
1419 | #endif | ||
1420 | }; | ||
1421 | |||
1422 | static int octeon_mgmt_probe(struct platform_device *pdev) | ||
1423 | { | ||
1424 | struct net_device *netdev; | ||
1425 | struct octeon_mgmt *p; | ||
1426 | const __be32 *data; | ||
1427 | const u8 *mac; | ||
1428 | struct resource *res_mix; | ||
1429 | struct resource *res_agl; | ||
1430 | struct resource *res_agl_prt_ctl; | ||
1431 | int len; | ||
1432 | int result; | ||
1433 | |||
1434 | netdev = alloc_etherdev(sizeof(struct octeon_mgmt)); | ||
1435 | if (netdev == NULL) | ||
1436 | return -ENOMEM; | ||
1437 | |||
1438 | SET_NETDEV_DEV(netdev, &pdev->dev); | ||
1439 | |||
1440 | dev_set_drvdata(&pdev->dev, netdev); | ||
1441 | p = netdev_priv(netdev); | ||
1442 | netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll, | ||
1443 | OCTEON_MGMT_NAPI_WEIGHT); | ||
1444 | |||
1445 | p->netdev = netdev; | ||
1446 | p->dev = &pdev->dev; | ||
1447 | p->has_rx_tstamp = false; | ||
1448 | |||
1449 | data = of_get_property(pdev->dev.of_node, "cell-index", &len); | ||
1450 | if (data && len == sizeof(*data)) { | ||
1451 | p->port = be32_to_cpup(data); | ||
1452 | } else { | ||
1453 | dev_err(&pdev->dev, "no 'cell-index' property\n"); | ||
1454 | result = -ENXIO; | ||
1455 | goto err; | ||
1456 | } | ||
1457 | |||
1458 | snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port); | ||
1459 | |||
1460 | result = platform_get_irq(pdev, 0); | ||
1461 | if (result < 0) | ||
1462 | goto err; | ||
1463 | |||
1464 | p->irq = result; | ||
1465 | |||
1466 | res_mix = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1467 | if (res_mix == NULL) { | ||
1468 | dev_err(&pdev->dev, "no 'reg' resource\n"); | ||
1469 | result = -ENXIO; | ||
1470 | goto err; | ||
1471 | } | ||
1472 | |||
1473 | res_agl = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1474 | if (res_agl == NULL) { | ||
1475 | dev_err(&pdev->dev, "no 'reg' resource\n"); | ||
1476 | result = -ENXIO; | ||
1477 | goto err; | ||
1478 | } | ||
1479 | |||
1480 | res_agl_prt_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 3); | ||
1481 | if (res_agl_prt_ctl == NULL) { | ||
1482 | dev_err(&pdev->dev, "no 'reg' resource\n"); | ||
1483 | result = -ENXIO; | ||
1484 | goto err; | ||
1485 | } | ||
1486 | |||
1487 | p->mix_phys = res_mix->start; | ||
1488 | p->mix_size = resource_size(res_mix); | ||
1489 | p->agl_phys = res_agl->start; | ||
1490 | p->agl_size = resource_size(res_agl); | ||
1491 | p->agl_prt_ctl_phys = res_agl_prt_ctl->start; | ||
1492 | p->agl_prt_ctl_size = resource_size(res_agl_prt_ctl); | ||
1493 | |||
1494 | |||
1495 | if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size, | ||
1496 | res_mix->name)) { | ||
1497 | dev_err(&pdev->dev, "request_mem_region (%s) failed\n", | ||
1498 | res_mix->name); | ||
1499 | result = -ENXIO; | ||
1500 | goto err; | ||
1501 | } | ||
1502 | |||
1503 | if (!devm_request_mem_region(&pdev->dev, p->agl_phys, p->agl_size, | ||
1504 | res_agl->name)) { | ||
1505 | result = -ENXIO; | ||
1506 | dev_err(&pdev->dev, "request_mem_region (%s) failed\n", | ||
1507 | res_agl->name); | ||
1508 | goto err; | ||
1509 | } | ||
1510 | |||
1511 | if (!devm_request_mem_region(&pdev->dev, p->agl_prt_ctl_phys, | ||
1512 | p->agl_prt_ctl_size, res_agl_prt_ctl->name)) { | ||
1513 | result = -ENXIO; | ||
1514 | dev_err(&pdev->dev, "request_mem_region (%s) failed\n", | ||
1515 | res_agl_prt_ctl->name); | ||
1516 | goto err; | ||
1517 | } | ||
1518 | |||
1519 | p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size); | ||
1520 | p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size); | ||
1521 | p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys, | ||
1522 | p->agl_prt_ctl_size); | ||
1523 | spin_lock_init(&p->lock); | ||
1524 | |||
1525 | skb_queue_head_init(&p->tx_list); | ||
1526 | skb_queue_head_init(&p->rx_list); | ||
1527 | tasklet_init(&p->tx_clean_tasklet, | ||
1528 | octeon_mgmt_clean_tx_tasklet, (unsigned long)p); | ||
1529 | |||
1530 | netdev->priv_flags |= IFF_UNICAST_FLT; | ||
1531 | |||
1532 | netdev->netdev_ops = &octeon_mgmt_ops; | ||
1533 | netdev->ethtool_ops = &octeon_mgmt_ethtool_ops; | ||
1534 | |||
1535 | mac = of_get_mac_address(pdev->dev.of_node); | ||
1536 | |||
1537 | if (mac && is_valid_ether_addr(mac)) { | ||
1538 | memcpy(netdev->dev_addr, mac, ETH_ALEN); | ||
1539 | netdev->addr_assign_type &= ~NET_ADDR_RANDOM; | ||
1540 | } else { | ||
1541 | eth_hw_addr_random(netdev); | ||
1542 | } | ||
1543 | |||
1544 | p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); | ||
1545 | |||
1546 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); | ||
1547 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; | ||
1548 | |||
1549 | netif_carrier_off(netdev); | ||
1550 | result = register_netdev(netdev); | ||
1551 | if (result) | ||
1552 | goto err; | ||
1553 | |||
1554 | dev_info(&pdev->dev, "Version " DRV_VERSION "\n"); | ||
1555 | return 0; | ||
1556 | |||
1557 | err: | ||
1558 | free_netdev(netdev); | ||
1559 | return result; | ||
1560 | } | ||
1561 | |||
1562 | static int octeon_mgmt_remove(struct platform_device *pdev) | ||
1563 | { | ||
1564 | struct net_device *netdev = dev_get_drvdata(&pdev->dev); | ||
1565 | |||
1566 | unregister_netdev(netdev); | ||
1567 | free_netdev(netdev); | ||
1568 | return 0; | ||
1569 | } | ||
1570 | |||
1571 | static struct of_device_id octeon_mgmt_match[] = { | ||
1572 | { | ||
1573 | .compatible = "cavium,octeon-5750-mix", | ||
1574 | }, | ||
1575 | {}, | ||
1576 | }; | ||
1577 | MODULE_DEVICE_TABLE(of, octeon_mgmt_match); | ||
1578 | |||
1579 | static struct platform_driver octeon_mgmt_driver = { | ||
1580 | .driver = { | ||
1581 | .name = "octeon_mgmt", | ||
1582 | .owner = THIS_MODULE, | ||
1583 | .of_match_table = octeon_mgmt_match, | ||
1584 | }, | ||
1585 | .probe = octeon_mgmt_probe, | ||
1586 | .remove = octeon_mgmt_remove, | ||
1587 | }; | ||
1588 | |||
1589 | extern void octeon_mdiobus_force_mod_depencency(void); | ||
1590 | |||
1591 | static int __init octeon_mgmt_mod_init(void) | ||
1592 | { | ||
1593 | /* Force our mdiobus driver module to be loaded first. */ | ||
1594 | octeon_mdiobus_force_mod_depencency(); | ||
1595 | return platform_driver_register(&octeon_mgmt_driver); | ||
1596 | } | ||
1597 | |||
1598 | static void __exit octeon_mgmt_mod_exit(void) | ||
1599 | { | ||
1600 | platform_driver_unregister(&octeon_mgmt_driver); | ||
1601 | } | ||
1602 | |||
1603 | module_init(octeon_mgmt_mod_init); | ||
1604 | module_exit(octeon_mgmt_mod_exit); | ||
1605 | |||
1606 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | ||
1607 | MODULE_AUTHOR("David Daney"); | ||
1608 | MODULE_LICENSE("GPL"); | ||
1609 | MODULE_VERSION(DRV_VERSION); | ||