1 | /* MOXA ART Ethernet (RTL8201CP) driver. |
2 | * |
3 | * Copyright (C) 2013 Jonas Jensen |
4 | * |
5 | * Jonas Jensen <jonas.jensen@gmail.com> |
6 | * |
7 | * Based on code from |
8 | * Moxa Technology Co., Ltd. <www.moxa.com> |
9 | * |
10 | * This file is licensed under the terms of the GNU General Public |
11 | * License version 2. This program is licensed "as is" without any |
12 | * warranty of any kind, whether express or implied. |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/netdevice.h> |
17 | #include <linux/etherdevice.h> |
18 | #include <linux/skbuff.h> |
19 | #include <linux/dma-mapping.h> |
20 | #include <linux/ethtool.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/interrupt.h> |
23 | #include <linux/irq.h> |
24 | #include <linux/of_address.h> |
25 | #include <linux/of_irq.h> |
26 | #include <linux/crc32.h> |
27 | #include <linux/crc32c.h> |
28 | #include <linux/circ_buf.h> |
29 | |
30 | #include "moxart_ether.h" |
31 | |
32 | static inline void moxart_desc_write(u32 data, __le32 *desc) |
33 | { |
34 | *desc = cpu_to_le32(data); |
35 | } |
36 | |
37 | static inline u32 moxart_desc_read(__le32 *desc) |
38 | { |
39 | return le32_to_cpu(*desc); |
40 | } |
41 | |
42 | static inline void moxart_emac_write(struct net_device *ndev, |
43 | unsigned int reg, unsigned long value) |
44 | { |
45 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
46 | |
47 | writel(val: value, addr: priv->base + reg); |
48 | } |
49 | |
50 | static void moxart_update_mac_address(struct net_device *ndev) |
51 | { |
52 | moxart_emac_write(ndev, REG_MAC_MS_ADDRESS, |
53 | value: ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]))); |
54 | moxart_emac_write(ndev, REG_MAC_MS_ADDRESS + 4, |
55 | value: ((ndev->dev_addr[2] << 24) | |
56 | (ndev->dev_addr[3] << 16) | |
57 | (ndev->dev_addr[4] << 8) | |
58 | (ndev->dev_addr[5]))); |
59 | } |
60 | |
61 | static int moxart_set_mac_address(struct net_device *ndev, void *addr) |
62 | { |
63 | struct sockaddr *address = addr; |
64 | |
65 | eth_hw_addr_set(dev: ndev, addr: address->sa_data); |
66 | moxart_update_mac_address(ndev); |
67 | |
68 | return 0; |
69 | } |
70 | |
71 | static void moxart_mac_free_memory(struct net_device *ndev) |
72 | { |
73 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
74 | |
75 | if (priv->tx_desc_base) |
76 | dma_free_coherent(dev: &priv->pdev->dev, |
77 | TX_REG_DESC_SIZE * TX_DESC_NUM, |
78 | cpu_addr: priv->tx_desc_base, dma_handle: priv->tx_base); |
79 | |
80 | if (priv->rx_desc_base) |
81 | dma_free_coherent(dev: &priv->pdev->dev, |
82 | RX_REG_DESC_SIZE * RX_DESC_NUM, |
83 | cpu_addr: priv->rx_desc_base, dma_handle: priv->rx_base); |
84 | |
85 | kfree(objp: priv->tx_buf_base); |
86 | kfree(objp: priv->rx_buf_base); |
87 | } |
88 | |
89 | static void moxart_mac_reset(struct net_device *ndev) |
90 | { |
91 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
92 | |
93 | writel(SW_RST, addr: priv->base + REG_MAC_CTRL); |
94 | while (readl(addr: priv->base + REG_MAC_CTRL) & SW_RST) |
95 | mdelay(10); |
96 | |
97 | writel(val: 0, addr: priv->base + REG_INTERRUPT_MASK); |
98 | |
99 | priv->reg_maccr = RX_BROADPKT | FULLDUP | CRC_APD | RX_FTL; |
100 | } |
101 | |
102 | static void moxart_mac_enable(struct net_device *ndev) |
103 | { |
104 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
105 | |
106 | writel(val: 0x00001010, addr: priv->base + REG_INT_TIMER_CTRL); |
107 | writel(val: 0x00000001, addr: priv->base + REG_APOLL_TIMER_CTRL); |
108 | writel(val: 0x00000390, addr: priv->base + REG_DMA_BLEN_CTRL); |
109 | |
110 | priv->reg_imr |= (RPKT_FINISH_M | XPKT_FINISH_M); |
111 | writel(val: priv->reg_imr, addr: priv->base + REG_INTERRUPT_MASK); |
112 | |
113 | priv->reg_maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN); |
114 | writel(val: priv->reg_maccr, addr: priv->base + REG_MAC_CTRL); |
115 | } |
116 | |
117 | static void moxart_mac_setup_desc_ring(struct net_device *ndev) |
118 | { |
119 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
120 | void *desc; |
121 | int i; |
122 | |
123 | for (i = 0; i < TX_DESC_NUM; i++) { |
124 | desc = priv->tx_desc_base + i * TX_REG_DESC_SIZE; |
125 | memset(desc, 0, TX_REG_DESC_SIZE); |
126 | |
127 | priv->tx_buf[i] = priv->tx_buf_base + priv->tx_buf_size * i; |
128 | } |
129 | moxart_desc_write(TX_DESC1_END, desc: desc + TX_REG_OFFSET_DESC1); |
130 | |
131 | priv->tx_head = 0; |
132 | priv->tx_tail = 0; |
133 | |
134 | for (i = 0; i < RX_DESC_NUM; i++) { |
135 | desc = priv->rx_desc_base + i * RX_REG_DESC_SIZE; |
136 | memset(desc, 0, RX_REG_DESC_SIZE); |
137 | moxart_desc_write(RX_DESC0_DMA_OWN, desc: desc + RX_REG_OFFSET_DESC0); |
138 | moxart_desc_write(RX_BUF_SIZE & RX_DESC1_BUF_SIZE_MASK, |
139 | desc: desc + RX_REG_OFFSET_DESC1); |
140 | |
141 | priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i; |
142 | priv->rx_mapping[i] = dma_map_single(&priv->pdev->dev, |
143 | priv->rx_buf[i], |
144 | priv->rx_buf_size, |
145 | DMA_FROM_DEVICE); |
146 | if (dma_mapping_error(dev: &priv->pdev->dev, dma_addr: priv->rx_mapping[i])) |
147 | netdev_err(dev: ndev, format: "DMA mapping error\n" ); |
148 | |
149 | moxart_desc_write(data: priv->rx_mapping[i], |
150 | desc: desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_PHYS); |
151 | moxart_desc_write(data: (uintptr_t)priv->rx_buf[i], |
152 | desc: desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_VIRT); |
153 | } |
154 | moxart_desc_write(RX_DESC1_END, desc: desc + RX_REG_OFFSET_DESC1); |
155 | |
156 | priv->rx_head = 0; |
157 | |
158 | /* reset the MAC controller TX/RX descriptor base address */ |
159 | writel(val: priv->tx_base, addr: priv->base + REG_TXR_BASE_ADDRESS); |
160 | writel(val: priv->rx_base, addr: priv->base + REG_RXR_BASE_ADDRESS); |
161 | } |
162 | |
163 | static int moxart_mac_open(struct net_device *ndev) |
164 | { |
165 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
166 | |
167 | napi_enable(n: &priv->napi); |
168 | |
169 | moxart_mac_reset(ndev); |
170 | moxart_update_mac_address(ndev); |
171 | moxart_mac_setup_desc_ring(ndev); |
172 | moxart_mac_enable(ndev); |
173 | netif_start_queue(dev: ndev); |
174 | |
175 | netdev_dbg(ndev, "%s: IMR=0x%x, MACCR=0x%x\n" , |
176 | __func__, readl(priv->base + REG_INTERRUPT_MASK), |
177 | readl(priv->base + REG_MAC_CTRL)); |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | static int moxart_mac_stop(struct net_device *ndev) |
183 | { |
184 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
185 | int i; |
186 | |
187 | napi_disable(n: &priv->napi); |
188 | |
189 | netif_stop_queue(dev: ndev); |
190 | |
191 | /* disable all interrupts */ |
192 | writel(val: 0, addr: priv->base + REG_INTERRUPT_MASK); |
193 | |
194 | /* disable all functions */ |
195 | writel(val: 0, addr: priv->base + REG_MAC_CTRL); |
196 | |
197 | /* unmap areas mapped in moxart_mac_setup_desc_ring() */ |
198 | for (i = 0; i < RX_DESC_NUM; i++) |
199 | dma_unmap_single(&priv->pdev->dev, priv->rx_mapping[i], |
200 | priv->rx_buf_size, DMA_FROM_DEVICE); |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | static int moxart_rx_poll(struct napi_struct *napi, int budget) |
206 | { |
207 | struct moxart_mac_priv_t *priv = container_of(napi, |
208 | struct moxart_mac_priv_t, |
209 | napi); |
210 | struct net_device *ndev = priv->ndev; |
211 | struct sk_buff *skb; |
212 | void *desc; |
213 | unsigned int desc0, len; |
214 | int rx_head = priv->rx_head; |
215 | int rx = 0; |
216 | |
217 | while (rx < budget) { |
218 | desc = priv->rx_desc_base + (RX_REG_DESC_SIZE * rx_head); |
219 | desc0 = moxart_desc_read(desc: desc + RX_REG_OFFSET_DESC0); |
220 | rmb(); /* ensure desc0 is up to date */ |
221 | |
222 | if (desc0 & RX_DESC0_DMA_OWN) |
223 | break; |
224 | |
225 | if (desc0 & (RX_DESC0_ERR | RX_DESC0_CRC_ERR | RX_DESC0_FTL | |
226 | RX_DESC0_RUNT | RX_DESC0_ODD_NB)) { |
227 | net_dbg_ratelimited("packet error\n" ); |
228 | ndev->stats.rx_dropped++; |
229 | ndev->stats.rx_errors++; |
230 | goto rx_next; |
231 | } |
232 | |
233 | len = desc0 & RX_DESC0_FRAME_LEN_MASK; |
234 | |
235 | if (len > RX_BUF_SIZE) |
236 | len = RX_BUF_SIZE; |
237 | |
238 | dma_sync_single_for_cpu(dev: &priv->pdev->dev, |
239 | addr: priv->rx_mapping[rx_head], |
240 | size: priv->rx_buf_size, dir: DMA_FROM_DEVICE); |
241 | skb = netdev_alloc_skb_ip_align(dev: ndev, length: len); |
242 | |
243 | if (unlikely(!skb)) { |
244 | net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n" ); |
245 | ndev->stats.rx_dropped++; |
246 | ndev->stats.rx_errors++; |
247 | goto rx_next; |
248 | } |
249 | |
250 | memcpy(skb->data, priv->rx_buf[rx_head], len); |
251 | skb_put(skb, len); |
252 | skb->protocol = eth_type_trans(skb, dev: ndev); |
253 | napi_gro_receive(napi: &priv->napi, skb); |
254 | rx++; |
255 | |
256 | ndev->stats.rx_packets++; |
257 | ndev->stats.rx_bytes += len; |
258 | if (desc0 & RX_DESC0_MULTICAST) |
259 | ndev->stats.multicast++; |
260 | |
261 | rx_next: |
262 | wmb(); /* prevent setting ownership back too early */ |
263 | moxart_desc_write(RX_DESC0_DMA_OWN, desc: desc + RX_REG_OFFSET_DESC0); |
264 | |
265 | rx_head = RX_NEXT(rx_head); |
266 | priv->rx_head = rx_head; |
267 | } |
268 | |
269 | if (rx < budget) |
270 | napi_complete_done(n: napi, work_done: rx); |
271 | |
272 | priv->reg_imr |= RPKT_FINISH_M; |
273 | writel(val: priv->reg_imr, addr: priv->base + REG_INTERRUPT_MASK); |
274 | |
275 | return rx; |
276 | } |
277 | |
278 | static int moxart_tx_queue_space(struct net_device *ndev) |
279 | { |
280 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
281 | |
282 | return CIRC_SPACE(priv->tx_head, priv->tx_tail, TX_DESC_NUM); |
283 | } |
284 | |
285 | static void moxart_tx_finished(struct net_device *ndev) |
286 | { |
287 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
288 | unsigned int tx_head = priv->tx_head; |
289 | unsigned int tx_tail = priv->tx_tail; |
290 | |
291 | while (tx_tail != tx_head) { |
292 | dma_unmap_single(&priv->pdev->dev, priv->tx_mapping[tx_tail], |
293 | priv->tx_len[tx_tail], DMA_TO_DEVICE); |
294 | |
295 | ndev->stats.tx_packets++; |
296 | ndev->stats.tx_bytes += priv->tx_skb[tx_tail]->len; |
297 | |
298 | dev_consume_skb_irq(skb: priv->tx_skb[tx_tail]); |
299 | priv->tx_skb[tx_tail] = NULL; |
300 | |
301 | tx_tail = TX_NEXT(tx_tail); |
302 | } |
303 | priv->tx_tail = tx_tail; |
304 | if (netif_queue_stopped(dev: ndev) && |
305 | moxart_tx_queue_space(ndev) >= TX_WAKE_THRESHOLD) |
306 | netif_wake_queue(dev: ndev); |
307 | } |
308 | |
309 | static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id) |
310 | { |
311 | struct net_device *ndev = (struct net_device *)dev_id; |
312 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
313 | unsigned int ists = readl(addr: priv->base + REG_INTERRUPT_STATUS); |
314 | |
315 | if (ists & XPKT_OK_INT_STS) |
316 | moxart_tx_finished(ndev); |
317 | |
318 | if (ists & RPKT_FINISH) { |
319 | if (napi_schedule_prep(n: &priv->napi)) { |
320 | priv->reg_imr &= ~RPKT_FINISH_M; |
321 | writel(val: priv->reg_imr, addr: priv->base + REG_INTERRUPT_MASK); |
322 | __napi_schedule(n: &priv->napi); |
323 | } |
324 | } |
325 | |
326 | return IRQ_HANDLED; |
327 | } |
328 | |
329 | static netdev_tx_t moxart_mac_start_xmit(struct sk_buff *skb, |
330 | struct net_device *ndev) |
331 | { |
332 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
333 | void *desc; |
334 | unsigned int len; |
335 | unsigned int tx_head; |
336 | u32 txdes1; |
337 | netdev_tx_t ret = NETDEV_TX_BUSY; |
338 | |
339 | spin_lock_irq(lock: &priv->txlock); |
340 | |
341 | tx_head = priv->tx_head; |
342 | desc = priv->tx_desc_base + (TX_REG_DESC_SIZE * tx_head); |
343 | |
344 | if (moxart_tx_queue_space(ndev) == 1) |
345 | netif_stop_queue(dev: ndev); |
346 | |
347 | if (moxart_desc_read(desc: desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) { |
348 | net_dbg_ratelimited("no TX space for packet\n" ); |
349 | ndev->stats.tx_dropped++; |
350 | goto out_unlock; |
351 | } |
352 | rmb(); /* ensure data is only read that had TX_DESC0_DMA_OWN cleared */ |
353 | |
354 | len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len; |
355 | |
356 | priv->tx_mapping[tx_head] = dma_map_single(&priv->pdev->dev, skb->data, |
357 | len, DMA_TO_DEVICE); |
358 | if (dma_mapping_error(dev: &priv->pdev->dev, dma_addr: priv->tx_mapping[tx_head])) { |
359 | netdev_err(dev: ndev, format: "DMA mapping error\n" ); |
360 | goto out_unlock; |
361 | } |
362 | |
363 | priv->tx_len[tx_head] = len; |
364 | priv->tx_skb[tx_head] = skb; |
365 | |
366 | moxart_desc_write(data: priv->tx_mapping[tx_head], |
367 | desc: desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_PHYS); |
368 | moxart_desc_write(data: (uintptr_t)skb->data, |
369 | desc: desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_VIRT); |
370 | |
371 | if (skb->len < ETH_ZLEN) { |
372 | memset(&skb->data[skb->len], |
373 | 0, ETH_ZLEN - skb->len); |
374 | len = ETH_ZLEN; |
375 | } |
376 | |
377 | dma_sync_single_for_device(dev: &priv->pdev->dev, addr: priv->tx_mapping[tx_head], |
378 | size: priv->tx_buf_size, dir: DMA_TO_DEVICE); |
379 | |
380 | txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | (len & TX_DESC1_BUF_SIZE_MASK); |
381 | if (tx_head == TX_DESC_NUM_MASK) |
382 | txdes1 |= TX_DESC1_END; |
383 | moxart_desc_write(data: txdes1, desc: desc + TX_REG_OFFSET_DESC1); |
384 | wmb(); /* flush descriptor before transferring ownership */ |
385 | moxart_desc_write(TX_DESC0_DMA_OWN, desc: desc + TX_REG_OFFSET_DESC0); |
386 | |
387 | /* start to send packet */ |
388 | writel(val: 0xffffffff, addr: priv->base + REG_TX_POLL_DEMAND); |
389 | |
390 | priv->tx_head = TX_NEXT(tx_head); |
391 | |
392 | netif_trans_update(dev: ndev); |
393 | ret = NETDEV_TX_OK; |
394 | out_unlock: |
395 | spin_unlock_irq(lock: &priv->txlock); |
396 | |
397 | return ret; |
398 | } |
399 | |
400 | static void moxart_mac_setmulticast(struct net_device *ndev) |
401 | { |
402 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
403 | struct netdev_hw_addr *ha; |
404 | int crc_val; |
405 | |
406 | netdev_for_each_mc_addr(ha, ndev) { |
407 | crc_val = crc32_le(crc: ~0, p: ha->addr, ETH_ALEN); |
408 | crc_val = (crc_val >> 26) & 0x3f; |
409 | if (crc_val >= 32) { |
410 | writel(readl(addr: priv->base + REG_MCAST_HASH_TABLE1) | |
411 | (1UL << (crc_val - 32)), |
412 | addr: priv->base + REG_MCAST_HASH_TABLE1); |
413 | } else { |
414 | writel(readl(addr: priv->base + REG_MCAST_HASH_TABLE0) | |
415 | (1UL << crc_val), |
416 | addr: priv->base + REG_MCAST_HASH_TABLE0); |
417 | } |
418 | } |
419 | } |
420 | |
421 | static void moxart_mac_set_rx_mode(struct net_device *ndev) |
422 | { |
423 | struct moxart_mac_priv_t *priv = netdev_priv(dev: ndev); |
424 | |
425 | spin_lock_irq(lock: &priv->txlock); |
426 | |
427 | (ndev->flags & IFF_PROMISC) ? (priv->reg_maccr |= RCV_ALL) : |
428 | (priv->reg_maccr &= ~RCV_ALL); |
429 | |
430 | (ndev->flags & IFF_ALLMULTI) ? (priv->reg_maccr |= RX_MULTIPKT) : |
431 | (priv->reg_maccr &= ~RX_MULTIPKT); |
432 | |
433 | if ((ndev->flags & IFF_MULTICAST) && netdev_mc_count(ndev)) { |
434 | priv->reg_maccr |= HT_MULTI_EN; |
435 | moxart_mac_setmulticast(ndev); |
436 | } else { |
437 | priv->reg_maccr &= ~HT_MULTI_EN; |
438 | } |
439 | |
440 | writel(val: priv->reg_maccr, addr: priv->base + REG_MAC_CTRL); |
441 | |
442 | spin_unlock_irq(lock: &priv->txlock); |
443 | } |
444 | |
445 | static const struct net_device_ops moxart_netdev_ops = { |
446 | .ndo_open = moxart_mac_open, |
447 | .ndo_stop = moxart_mac_stop, |
448 | .ndo_start_xmit = moxart_mac_start_xmit, |
449 | .ndo_set_rx_mode = moxart_mac_set_rx_mode, |
450 | .ndo_set_mac_address = moxart_set_mac_address, |
451 | .ndo_validate_addr = eth_validate_addr, |
452 | }; |
453 | |
454 | static int moxart_mac_probe(struct platform_device *pdev) |
455 | { |
456 | struct device *p_dev = &pdev->dev; |
457 | struct device_node *node = p_dev->of_node; |
458 | struct net_device *ndev; |
459 | struct moxart_mac_priv_t *priv; |
460 | struct resource *res; |
461 | unsigned int irq; |
462 | int ret; |
463 | |
464 | ndev = alloc_etherdev(sizeof(struct moxart_mac_priv_t)); |
465 | if (!ndev) |
466 | return -ENOMEM; |
467 | |
468 | irq = irq_of_parse_and_map(node, index: 0); |
469 | if (irq <= 0) { |
470 | netdev_err(dev: ndev, format: "irq_of_parse_and_map failed\n" ); |
471 | ret = -EINVAL; |
472 | goto irq_map_fail; |
473 | } |
474 | |
475 | priv = netdev_priv(dev: ndev); |
476 | priv->ndev = ndev; |
477 | priv->pdev = pdev; |
478 | |
479 | priv->base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
480 | if (IS_ERR(ptr: priv->base)) { |
481 | ret = PTR_ERR(ptr: priv->base); |
482 | goto init_fail; |
483 | } |
484 | ndev->base_addr = res->start; |
485 | |
486 | ret = platform_get_ethdev_address(dev: p_dev, netdev: ndev); |
487 | if (ret == -EPROBE_DEFER) |
488 | goto init_fail; |
489 | if (ret) |
490 | eth_hw_addr_random(dev: ndev); |
491 | moxart_update_mac_address(ndev); |
492 | |
493 | spin_lock_init(&priv->txlock); |
494 | |
495 | priv->tx_buf_size = TX_BUF_SIZE; |
496 | priv->rx_buf_size = RX_BUF_SIZE; |
497 | |
498 | priv->tx_desc_base = dma_alloc_coherent(dev: p_dev, TX_REG_DESC_SIZE * |
499 | TX_DESC_NUM, dma_handle: &priv->tx_base, |
500 | GFP_DMA | GFP_KERNEL); |
501 | if (!priv->tx_desc_base) { |
502 | ret = -ENOMEM; |
503 | goto init_fail; |
504 | } |
505 | |
506 | priv->rx_desc_base = dma_alloc_coherent(dev: p_dev, RX_REG_DESC_SIZE * |
507 | RX_DESC_NUM, dma_handle: &priv->rx_base, |
508 | GFP_DMA | GFP_KERNEL); |
509 | if (!priv->rx_desc_base) { |
510 | ret = -ENOMEM; |
511 | goto init_fail; |
512 | } |
513 | |
514 | priv->tx_buf_base = kmalloc_array(n: priv->tx_buf_size, TX_DESC_NUM, |
515 | GFP_KERNEL); |
516 | if (!priv->tx_buf_base) { |
517 | ret = -ENOMEM; |
518 | goto init_fail; |
519 | } |
520 | |
521 | priv->rx_buf_base = kmalloc_array(n: priv->rx_buf_size, RX_DESC_NUM, |
522 | GFP_KERNEL); |
523 | if (!priv->rx_buf_base) { |
524 | ret = -ENOMEM; |
525 | goto init_fail; |
526 | } |
527 | |
528 | platform_set_drvdata(pdev, data: ndev); |
529 | |
530 | ret = devm_request_irq(dev: p_dev, irq, handler: moxart_mac_interrupt, irqflags: 0, |
531 | devname: pdev->name, dev_id: ndev); |
532 | if (ret) { |
533 | netdev_err(dev: ndev, format: "devm_request_irq failed\n" ); |
534 | goto init_fail; |
535 | } |
536 | |
537 | ndev->netdev_ops = &moxart_netdev_ops; |
538 | netif_napi_add_weight(dev: ndev, napi: &priv->napi, poll: moxart_rx_poll, RX_DESC_NUM); |
539 | ndev->priv_flags |= IFF_UNICAST_FLT; |
540 | ndev->irq = irq; |
541 | |
542 | SET_NETDEV_DEV(ndev, &pdev->dev); |
543 | |
544 | ret = register_netdev(dev: ndev); |
545 | if (ret) |
546 | goto init_fail; |
547 | |
548 | netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n" , |
549 | __func__, ndev->irq, ndev->dev_addr); |
550 | |
551 | return 0; |
552 | |
553 | init_fail: |
554 | netdev_err(dev: ndev, format: "init failed\n" ); |
555 | moxart_mac_free_memory(ndev); |
556 | irq_map_fail: |
557 | free_netdev(dev: ndev); |
558 | return ret; |
559 | } |
560 | |
561 | static void moxart_remove(struct platform_device *pdev) |
562 | { |
563 | struct net_device *ndev = platform_get_drvdata(pdev); |
564 | |
565 | unregister_netdev(dev: ndev); |
566 | devm_free_irq(dev: &pdev->dev, irq: ndev->irq, dev_id: ndev); |
567 | moxart_mac_free_memory(ndev); |
568 | free_netdev(dev: ndev); |
569 | } |
570 | |
571 | static const struct of_device_id moxart_mac_match[] = { |
572 | { .compatible = "moxa,moxart-mac" }, |
573 | { } |
574 | }; |
575 | MODULE_DEVICE_TABLE(of, moxart_mac_match); |
576 | |
577 | static struct platform_driver moxart_mac_driver = { |
578 | .probe = moxart_mac_probe, |
579 | .remove_new = moxart_remove, |
580 | .driver = { |
581 | .name = "moxart-ethernet" , |
582 | .of_match_table = moxart_mac_match, |
583 | }, |
584 | }; |
585 | module_platform_driver(moxart_mac_driver); |
586 | |
587 | MODULE_DESCRIPTION("MOXART RTL8201CP Ethernet driver" ); |
588 | MODULE_LICENSE("GPL v2" ); |
589 | MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>" ); |
590 | |