diff options
Diffstat (limited to 'drivers/net/ethernet/moxa/moxart_ether.c')
-rw-r--r-- | drivers/net/ethernet/moxa/moxart_ether.c | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c new file mode 100644 index 000000000000..83c2091c9c23 --- /dev/null +++ b/drivers/net/ethernet/moxa/moxart_ether.c | |||
@@ -0,0 +1,559 @@ | |||
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/init.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/skbuff.h> | ||
20 | #include <linux/dma-mapping.h> | ||
21 | #include <linux/ethtool.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_irq.h> | ||
27 | #include <linux/crc32.h> | ||
28 | #include <linux/crc32c.h> | ||
29 | #include <linux/dma-mapping.h> | ||
30 | |||
31 | #include "moxart_ether.h" | ||
32 | |||
33 | static inline void moxart_emac_write(struct net_device *ndev, | ||
34 | unsigned int reg, unsigned long value) | ||
35 | { | ||
36 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
37 | |||
38 | writel(value, priv->base + reg); | ||
39 | } | ||
40 | |||
41 | static void moxart_update_mac_address(struct net_device *ndev) | ||
42 | { | ||
43 | moxart_emac_write(ndev, REG_MAC_MS_ADDRESS, | ||
44 | ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]))); | ||
45 | moxart_emac_write(ndev, REG_MAC_MS_ADDRESS + 4, | ||
46 | ((ndev->dev_addr[2] << 24) | | ||
47 | (ndev->dev_addr[3] << 16) | | ||
48 | (ndev->dev_addr[4] << 8) | | ||
49 | (ndev->dev_addr[5]))); | ||
50 | } | ||
51 | |||
52 | static int moxart_set_mac_address(struct net_device *ndev, void *addr) | ||
53 | { | ||
54 | struct sockaddr *address = addr; | ||
55 | |||
56 | if (!is_valid_ether_addr(address->sa_data)) | ||
57 | return -EADDRNOTAVAIL; | ||
58 | |||
59 | memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); | ||
60 | moxart_update_mac_address(ndev); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void moxart_mac_free_memory(struct net_device *ndev) | ||
66 | { | ||
67 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
68 | int i; | ||
69 | |||
70 | for (i = 0; i < RX_DESC_NUM; i++) | ||
71 | dma_unmap_single(&ndev->dev, priv->rx_mapping[i], | ||
72 | priv->rx_buf_size, DMA_FROM_DEVICE); | ||
73 | |||
74 | if (priv->tx_desc_base) | ||
75 | dma_free_coherent(NULL, TX_REG_DESC_SIZE * TX_DESC_NUM, | ||
76 | priv->tx_desc_base, priv->tx_base); | ||
77 | |||
78 | if (priv->rx_desc_base) | ||
79 | dma_free_coherent(NULL, RX_REG_DESC_SIZE * RX_DESC_NUM, | ||
80 | priv->rx_desc_base, priv->rx_base); | ||
81 | |||
82 | kfree(priv->tx_buf_base); | ||
83 | kfree(priv->rx_buf_base); | ||
84 | } | ||
85 | |||
86 | static void moxart_mac_reset(struct net_device *ndev) | ||
87 | { | ||
88 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
89 | |||
90 | writel(SW_RST, priv->base + REG_MAC_CTRL); | ||
91 | while (readl(priv->base + REG_MAC_CTRL) & SW_RST) | ||
92 | mdelay(10); | ||
93 | |||
94 | writel(0, priv->base + REG_INTERRUPT_MASK); | ||
95 | |||
96 | priv->reg_maccr = RX_BROADPKT | FULLDUP | CRC_APD | RX_FTL; | ||
97 | } | ||
98 | |||
99 | static void moxart_mac_enable(struct net_device *ndev) | ||
100 | { | ||
101 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
102 | |||
103 | writel(0x00001010, priv->base + REG_INT_TIMER_CTRL); | ||
104 | writel(0x00000001, priv->base + REG_APOLL_TIMER_CTRL); | ||
105 | writel(0x00000390, priv->base + REG_DMA_BLEN_CTRL); | ||
106 | |||
107 | priv->reg_imr |= (RPKT_FINISH_M | XPKT_FINISH_M); | ||
108 | writel(priv->reg_imr, priv->base + REG_INTERRUPT_MASK); | ||
109 | |||
110 | priv->reg_maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN); | ||
111 | writel(priv->reg_maccr, priv->base + REG_MAC_CTRL); | ||
112 | } | ||
113 | |||
114 | static void moxart_mac_setup_desc_ring(struct net_device *ndev) | ||
115 | { | ||
116 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
117 | void __iomem *desc; | ||
118 | int i; | ||
119 | |||
120 | for (i = 0; i < TX_DESC_NUM; i++) { | ||
121 | desc = priv->tx_desc_base + i * TX_REG_DESC_SIZE; | ||
122 | memset(desc, 0, TX_REG_DESC_SIZE); | ||
123 | |||
124 | priv->tx_buf[i] = priv->tx_buf_base + priv->tx_buf_size * i; | ||
125 | } | ||
126 | writel(TX_DESC1_END, desc + TX_REG_OFFSET_DESC1); | ||
127 | |||
128 | priv->tx_head = 0; | ||
129 | priv->tx_tail = 0; | ||
130 | |||
131 | for (i = 0; i < RX_DESC_NUM; i++) { | ||
132 | desc = priv->rx_desc_base + i * RX_REG_DESC_SIZE; | ||
133 | memset(desc, 0, RX_REG_DESC_SIZE); | ||
134 | writel(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0); | ||
135 | writel(RX_BUF_SIZE & RX_DESC1_BUF_SIZE_MASK, | ||
136 | desc + RX_REG_OFFSET_DESC1); | ||
137 | |||
138 | priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i; | ||
139 | priv->rx_mapping[i] = dma_map_single(&ndev->dev, | ||
140 | priv->rx_buf[i], | ||
141 | priv->rx_buf_size, | ||
142 | DMA_FROM_DEVICE); | ||
143 | if (dma_mapping_error(&ndev->dev, priv->rx_mapping[i])) | ||
144 | netdev_err(ndev, "DMA mapping error\n"); | ||
145 | |||
146 | writel(priv->rx_mapping[i], | ||
147 | desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_PHYS); | ||
148 | writel(priv->rx_buf[i], | ||
149 | desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_VIRT); | ||
150 | } | ||
151 | writel(RX_DESC1_END, desc + RX_REG_OFFSET_DESC1); | ||
152 | |||
153 | priv->rx_head = 0; | ||
154 | |||
155 | /* reset the MAC controler TX/RX desciptor base address */ | ||
156 | writel(priv->tx_base, priv->base + REG_TXR_BASE_ADDRESS); | ||
157 | writel(priv->rx_base, priv->base + REG_RXR_BASE_ADDRESS); | ||
158 | } | ||
159 | |||
160 | static int moxart_mac_open(struct net_device *ndev) | ||
161 | { | ||
162 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
163 | |||
164 | if (!is_valid_ether_addr(ndev->dev_addr)) | ||
165 | return -EADDRNOTAVAIL; | ||
166 | |||
167 | napi_enable(&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(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(ndev); | ||
185 | |||
186 | napi_disable(&priv->napi); | ||
187 | |||
188 | netif_stop_queue(ndev); | ||
189 | |||
190 | /* disable all interrupts */ | ||
191 | writel(0, priv->base + REG_INTERRUPT_MASK); | ||
192 | |||
193 | /* disable all functions */ | ||
194 | writel(0, priv->base + REG_MAC_CTRL); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int moxart_rx_poll(struct napi_struct *napi, int budget) | ||
200 | { | ||
201 | struct moxart_mac_priv_t *priv = container_of(napi, | ||
202 | struct moxart_mac_priv_t, | ||
203 | napi); | ||
204 | struct net_device *ndev = priv->ndev; | ||
205 | struct sk_buff *skb; | ||
206 | void __iomem *desc; | ||
207 | unsigned int desc0, len; | ||
208 | int rx_head = priv->rx_head; | ||
209 | int rx = 0; | ||
210 | |||
211 | while (1) { | ||
212 | desc = priv->rx_desc_base + (RX_REG_DESC_SIZE * rx_head); | ||
213 | desc0 = readl(desc + RX_REG_OFFSET_DESC0); | ||
214 | |||
215 | if (desc0 & RX_DESC0_DMA_OWN) | ||
216 | break; | ||
217 | |||
218 | if (desc0 & (RX_DESC0_ERR | RX_DESC0_CRC_ERR | RX_DESC0_FTL | | ||
219 | RX_DESC0_RUNT | RX_DESC0_ODD_NB)) { | ||
220 | net_dbg_ratelimited("packet error\n"); | ||
221 | priv->stats.rx_dropped++; | ||
222 | priv->stats.rx_errors++; | ||
223 | continue; | ||
224 | } | ||
225 | |||
226 | len = desc0 & RX_DESC0_FRAME_LEN_MASK; | ||
227 | |||
228 | if (len > RX_BUF_SIZE) | ||
229 | len = RX_BUF_SIZE; | ||
230 | |||
231 | skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size); | ||
232 | if (unlikely(!skb)) { | ||
233 | net_dbg_ratelimited("build_skb failed\n"); | ||
234 | priv->stats.rx_dropped++; | ||
235 | priv->stats.rx_errors++; | ||
236 | } | ||
237 | |||
238 | skb_put(skb, len); | ||
239 | skb->protocol = eth_type_trans(skb, ndev); | ||
240 | napi_gro_receive(&priv->napi, skb); | ||
241 | rx++; | ||
242 | |||
243 | ndev->last_rx = jiffies; | ||
244 | priv->stats.rx_packets++; | ||
245 | priv->stats.rx_bytes += len; | ||
246 | if (desc0 & RX_DESC0_MULTICAST) | ||
247 | priv->stats.multicast++; | ||
248 | |||
249 | writel(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0); | ||
250 | |||
251 | rx_head = RX_NEXT(rx_head); | ||
252 | priv->rx_head = rx_head; | ||
253 | |||
254 | if (rx >= budget) | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | if (rx < budget) { | ||
259 | napi_gro_flush(napi, false); | ||
260 | __napi_complete(napi); | ||
261 | } | ||
262 | |||
263 | priv->reg_imr |= RPKT_FINISH_M; | ||
264 | writel(priv->reg_imr, priv->base + REG_INTERRUPT_MASK); | ||
265 | |||
266 | return rx; | ||
267 | } | ||
268 | |||
269 | static void moxart_tx_finished(struct net_device *ndev) | ||
270 | { | ||
271 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
272 | unsigned tx_head = priv->tx_head; | ||
273 | unsigned tx_tail = priv->tx_tail; | ||
274 | |||
275 | while (tx_tail != tx_head) { | ||
276 | dma_unmap_single(&ndev->dev, priv->tx_mapping[tx_tail], | ||
277 | priv->tx_len[tx_tail], DMA_TO_DEVICE); | ||
278 | |||
279 | priv->stats.tx_packets++; | ||
280 | priv->stats.tx_bytes += priv->tx_skb[tx_tail]->len; | ||
281 | |||
282 | dev_kfree_skb_irq(priv->tx_skb[tx_tail]); | ||
283 | priv->tx_skb[tx_tail] = NULL; | ||
284 | |||
285 | tx_tail = TX_NEXT(tx_tail); | ||
286 | } | ||
287 | priv->tx_tail = tx_tail; | ||
288 | } | ||
289 | |||
290 | static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id) | ||
291 | { | ||
292 | struct net_device *ndev = (struct net_device *) dev_id; | ||
293 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
294 | unsigned int ists = readl(priv->base + REG_INTERRUPT_STATUS); | ||
295 | |||
296 | if (ists & XPKT_OK_INT_STS) | ||
297 | moxart_tx_finished(ndev); | ||
298 | |||
299 | if (ists & RPKT_FINISH) { | ||
300 | if (napi_schedule_prep(&priv->napi)) { | ||
301 | priv->reg_imr &= ~RPKT_FINISH_M; | ||
302 | writel(priv->reg_imr, priv->base + REG_INTERRUPT_MASK); | ||
303 | __napi_schedule(&priv->napi); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | return IRQ_HANDLED; | ||
308 | } | ||
309 | |||
310 | static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) | ||
311 | { | ||
312 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
313 | void __iomem *desc; | ||
314 | unsigned int len; | ||
315 | unsigned int tx_head = priv->tx_head; | ||
316 | u32 txdes1; | ||
317 | int ret = NETDEV_TX_BUSY; | ||
318 | |||
319 | desc = priv->tx_desc_base + (TX_REG_DESC_SIZE * tx_head); | ||
320 | |||
321 | spin_lock_irq(&priv->txlock); | ||
322 | if (readl(desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) { | ||
323 | net_dbg_ratelimited("no TX space for packet\n"); | ||
324 | priv->stats.tx_dropped++; | ||
325 | goto out_unlock; | ||
326 | } | ||
327 | |||
328 | len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len; | ||
329 | |||
330 | priv->tx_mapping[tx_head] = dma_map_single(&ndev->dev, skb->data, | ||
331 | len, DMA_TO_DEVICE); | ||
332 | if (dma_mapping_error(&ndev->dev, priv->tx_mapping[tx_head])) { | ||
333 | netdev_err(ndev, "DMA mapping error\n"); | ||
334 | goto out_unlock; | ||
335 | } | ||
336 | |||
337 | priv->tx_len[tx_head] = len; | ||
338 | priv->tx_skb[tx_head] = skb; | ||
339 | |||
340 | writel(priv->tx_mapping[tx_head], | ||
341 | desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_PHYS); | ||
342 | writel(skb->data, | ||
343 | desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_VIRT); | ||
344 | |||
345 | if (skb->len < ETH_ZLEN) { | ||
346 | memset(&skb->data[skb->len], | ||
347 | 0, ETH_ZLEN - skb->len); | ||
348 | len = ETH_ZLEN; | ||
349 | } | ||
350 | |||
351 | txdes1 = readl(desc + TX_REG_OFFSET_DESC1); | ||
352 | txdes1 |= TX_DESC1_LTS | TX_DESC1_FTS; | ||
353 | txdes1 &= ~(TX_DESC1_FIFO_COMPLETE | TX_DESC1_INTR_COMPLETE); | ||
354 | txdes1 |= (len & TX_DESC1_BUF_SIZE_MASK); | ||
355 | writel(txdes1, desc + TX_REG_OFFSET_DESC1); | ||
356 | writel(TX_DESC0_DMA_OWN, desc + TX_REG_OFFSET_DESC0); | ||
357 | |||
358 | /* start to send packet */ | ||
359 | writel(0xffffffff, priv->base + REG_TX_POLL_DEMAND); | ||
360 | |||
361 | priv->tx_head = TX_NEXT(tx_head); | ||
362 | |||
363 | ndev->trans_start = jiffies; | ||
364 | ret = NETDEV_TX_OK; | ||
365 | out_unlock: | ||
366 | spin_unlock_irq(&priv->txlock); | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | static struct net_device_stats *moxart_mac_get_stats(struct net_device *ndev) | ||
372 | { | ||
373 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
374 | |||
375 | return &priv->stats; | ||
376 | } | ||
377 | |||
378 | static void moxart_mac_setmulticast(struct net_device *ndev) | ||
379 | { | ||
380 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
381 | struct netdev_hw_addr *ha; | ||
382 | int crc_val; | ||
383 | |||
384 | netdev_for_each_mc_addr(ha, ndev) { | ||
385 | crc_val = crc32_le(~0, ha->addr, ETH_ALEN); | ||
386 | crc_val = (crc_val >> 26) & 0x3f; | ||
387 | if (crc_val >= 32) { | ||
388 | writel(readl(priv->base + REG_MCAST_HASH_TABLE1) | | ||
389 | (1UL << (crc_val - 32)), | ||
390 | priv->base + REG_MCAST_HASH_TABLE1); | ||
391 | } else { | ||
392 | writel(readl(priv->base + REG_MCAST_HASH_TABLE0) | | ||
393 | (1UL << crc_val), | ||
394 | priv->base + REG_MCAST_HASH_TABLE0); | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | static void moxart_mac_set_rx_mode(struct net_device *ndev) | ||
400 | { | ||
401 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
402 | |||
403 | spin_lock_irq(&priv->txlock); | ||
404 | |||
405 | (ndev->flags & IFF_PROMISC) ? (priv->reg_maccr |= RCV_ALL) : | ||
406 | (priv->reg_maccr &= ~RCV_ALL); | ||
407 | |||
408 | (ndev->flags & IFF_ALLMULTI) ? (priv->reg_maccr |= RX_MULTIPKT) : | ||
409 | (priv->reg_maccr &= ~RX_MULTIPKT); | ||
410 | |||
411 | if ((ndev->flags & IFF_MULTICAST) && netdev_mc_count(ndev)) { | ||
412 | priv->reg_maccr |= HT_MULTI_EN; | ||
413 | moxart_mac_setmulticast(ndev); | ||
414 | } else { | ||
415 | priv->reg_maccr &= ~HT_MULTI_EN; | ||
416 | } | ||
417 | |||
418 | writel(priv->reg_maccr, priv->base + REG_MAC_CTRL); | ||
419 | |||
420 | spin_unlock_irq(&priv->txlock); | ||
421 | } | ||
422 | |||
423 | static struct net_device_ops moxart_netdev_ops = { | ||
424 | .ndo_open = moxart_mac_open, | ||
425 | .ndo_stop = moxart_mac_stop, | ||
426 | .ndo_start_xmit = moxart_mac_start_xmit, | ||
427 | .ndo_get_stats = moxart_mac_get_stats, | ||
428 | .ndo_set_rx_mode = moxart_mac_set_rx_mode, | ||
429 | .ndo_set_mac_address = moxart_set_mac_address, | ||
430 | .ndo_validate_addr = eth_validate_addr, | ||
431 | .ndo_change_mtu = eth_change_mtu, | ||
432 | }; | ||
433 | |||
434 | static int moxart_mac_probe(struct platform_device *pdev) | ||
435 | { | ||
436 | struct device *p_dev = &pdev->dev; | ||
437 | struct device_node *node = p_dev->of_node; | ||
438 | struct net_device *ndev; | ||
439 | struct moxart_mac_priv_t *priv; | ||
440 | struct resource *res; | ||
441 | unsigned int irq; | ||
442 | int ret; | ||
443 | |||
444 | ndev = alloc_etherdev(sizeof(struct moxart_mac_priv_t)); | ||
445 | if (!ndev) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | irq = irq_of_parse_and_map(node, 0); | ||
449 | if (irq <= 0) { | ||
450 | netdev_err(ndev, "irq_of_parse_and_map failed\n"); | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | priv = netdev_priv(ndev); | ||
455 | priv->ndev = ndev; | ||
456 | |||
457 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
458 | ndev->base_addr = res->start; | ||
459 | priv->base = devm_ioremap_resource(p_dev, res); | ||
460 | ret = IS_ERR(priv->base); | ||
461 | if (ret) { | ||
462 | dev_err(p_dev, "devm_ioremap_resource failed\n"); | ||
463 | goto init_fail; | ||
464 | } | ||
465 | |||
466 | spin_lock_init(&priv->txlock); | ||
467 | |||
468 | priv->tx_buf_size = TX_BUF_SIZE; | ||
469 | priv->rx_buf_size = RX_BUF_SIZE + | ||
470 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | ||
471 | |||
472 | priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE * | ||
473 | TX_DESC_NUM, &priv->tx_base, | ||
474 | GFP_DMA | GFP_KERNEL); | ||
475 | if (priv->tx_desc_base == NULL) | ||
476 | goto init_fail; | ||
477 | |||
478 | priv->rx_desc_base = dma_alloc_coherent(NULL, RX_REG_DESC_SIZE * | ||
479 | RX_DESC_NUM, &priv->rx_base, | ||
480 | GFP_DMA | GFP_KERNEL); | ||
481 | if (priv->rx_desc_base == NULL) | ||
482 | goto init_fail; | ||
483 | |||
484 | priv->tx_buf_base = kmalloc(priv->tx_buf_size * TX_DESC_NUM, | ||
485 | GFP_ATOMIC); | ||
486 | if (!priv->tx_buf_base) | ||
487 | goto init_fail; | ||
488 | |||
489 | priv->rx_buf_base = kmalloc(priv->rx_buf_size * RX_DESC_NUM, | ||
490 | GFP_ATOMIC); | ||
491 | if (!priv->rx_buf_base) | ||
492 | goto init_fail; | ||
493 | |||
494 | platform_set_drvdata(pdev, ndev); | ||
495 | |||
496 | ret = devm_request_irq(p_dev, irq, moxart_mac_interrupt, 0, | ||
497 | pdev->name, ndev); | ||
498 | if (ret) { | ||
499 | netdev_err(ndev, "devm_request_irq failed\n"); | ||
500 | goto init_fail; | ||
501 | } | ||
502 | |||
503 | ether_setup(ndev); | ||
504 | ndev->netdev_ops = &moxart_netdev_ops; | ||
505 | netif_napi_add(ndev, &priv->napi, moxart_rx_poll, RX_DESC_NUM); | ||
506 | ndev->priv_flags |= IFF_UNICAST_FLT; | ||
507 | ndev->irq = irq; | ||
508 | |||
509 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
510 | |||
511 | ret = register_netdev(ndev); | ||
512 | if (ret) { | ||
513 | free_netdev(ndev); | ||
514 | goto init_fail; | ||
515 | } | ||
516 | |||
517 | netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n", | ||
518 | __func__, ndev->irq, ndev->dev_addr); | ||
519 | |||
520 | return 0; | ||
521 | |||
522 | init_fail: | ||
523 | netdev_err(ndev, "init failed\n"); | ||
524 | moxart_mac_free_memory(ndev); | ||
525 | |||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static int moxart_remove(struct platform_device *pdev) | ||
530 | { | ||
531 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
532 | |||
533 | unregister_netdev(ndev); | ||
534 | free_irq(ndev->irq, ndev); | ||
535 | moxart_mac_free_memory(ndev); | ||
536 | free_netdev(ndev); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static const struct of_device_id moxart_mac_match[] = { | ||
542 | { .compatible = "moxa,moxart-mac" }, | ||
543 | { } | ||
544 | }; | ||
545 | |||
546 | struct __initdata platform_driver moxart_mac_driver = { | ||
547 | .probe = moxart_mac_probe, | ||
548 | .remove = moxart_remove, | ||
549 | .driver = { | ||
550 | .name = "moxart-ethernet", | ||
551 | .owner = THIS_MODULE, | ||
552 | .of_match_table = moxart_mac_match, | ||
553 | }, | ||
554 | }; | ||
555 | module_platform_driver(moxart_mac_driver); | ||
556 | |||
557 | MODULE_DESCRIPTION("MOXART RTL8201CP Ethernet driver"); | ||
558 | MODULE_LICENSE("GPL v2"); | ||
559 | MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); | ||