]> git.enpas.org Git - openwrt.git/blob - target/linux/ifxmips/files/drivers/net/ifxmips_mii0.c
[ifxmips] some cleanups:
[openwrt.git] / target / linux / ifxmips / files / drivers / net / ifxmips_mii0.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15  *
16  *   Copyright (C) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
17  *   Copyright (C) 2008 John Crispin <blogic@openwrt.org>
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/errno.h>
23 #include <linux/types.h>
24 #include <linux/interrupt.h>
25 #include <linux/uaccess.h>
26 #include <linux/in.h>
27 #include <linux/netdevice.h>
28 #include <linux/etherdevice.h>
29 #include <linux/ip.h>
30 #include <linux/tcp.h>
31 #include <linux/skbuff.h>
32 #include <linux/mm.h>
33 #include <linux/platform_device.h>
34 #include <linux/ethtool.h>
35 #include <linux/init.h>
36 #include <linux/delay.h>
37 #include <asm/checksum.h>
38 #include <asm/ifxmips/ifxmips.h>
39 #include <asm/ifxmips/ifxmips_dma.h>
40 #include <asm/ifxmips/ifxmips_pmu.h>
41
42 struct ifxmips_mii_priv {
43         struct net_device_stats stats;
44         struct dma_device_info *dma_device;
45         struct sk_buff *skb;
46 };
47
48 static struct net_device *ifxmips_mii0_dev;
49 static unsigned char mac_addr[MAX_ADDR_LEN];
50
51 void
52 ifxmips_write_mdio(u32 phy_addr, u32 phy_reg, u16 phy_data)
53 {
54         u32 val = MDIO_ACC_REQUEST |
55                 ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
56                 ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) |
57                 phy_data;
58
59         while(ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST);
60         ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
61 }
62 EXPORT_SYMBOL(ifxmips_write_mdio);
63
64 unsigned short
65 ifxmips_read_mdio(u32 phy_addr, u32 phy_reg)
66 {
67         u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ |
68                 ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
69                 ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET);
70
71         while(ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST);
72         ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
73         while(ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST){};
74         val = ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK;
75         return val;
76 }
77 EXPORT_SYMBOL(ifxmips_read_mdio);
78
79 int
80 ifxmips_ifxmips_mii_open(struct net_device *dev)
81 {
82         struct ifxmips_mii_priv* priv = (struct ifxmips_mii_priv*)dev->priv;
83         struct dma_device_info* dma_dev = priv->dma_device;
84         int i;
85
86         for (i = 0; i < dma_dev->max_rx_chan_num; i++)
87         {
88                 if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON)
89                         (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]);
90         }
91         netif_start_queue(dev);
92         return 0;
93 }
94
95 int
96 ifxmips_mii_release(struct net_device *dev){
97         struct ifxmips_mii_priv* priv = (struct ifxmips_mii_priv*)dev->priv;
98         struct dma_device_info* dma_dev = priv->dma_device;
99         int i;
100
101         for (i = 0; i < dma_dev->max_rx_chan_num; i++)
102                 dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
103         netif_stop_queue(dev);
104         return 0;
105 }
106
107 int
108 ifxmips_mii_hw_receive(struct net_device* dev,struct dma_device_info* dma_dev)
109 {
110         struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv*)dev->priv;
111         unsigned char* buf = NULL;
112         struct sk_buff *skb = NULL;
113         int len = 0;
114
115         len = dma_device_read(dma_dev, &buf, (void**)&skb);
116
117         if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE)
118         {
119                 printk(KERN_INFO "ifxmips_mii0: packet too large %d\n",len);
120                 goto ifxmips_mii_hw_receive_err_exit;
121         }
122
123         /* remove CRC */
124         len -= 4;
125         if (skb == NULL)
126         {
127                 printk(KERN_INFO "ifxmips_mii0: cannot restore pointer\n");
128                 goto ifxmips_mii_hw_receive_err_exit;
129         }
130
131         if (len > (skb->end - skb->tail))
132         {
133                 printk(KERN_INFO "ifxmips_mii0: BUG, len:%d end:%p tail:%p\n",
134                         (len+4), skb->end, skb->tail);
135                 goto ifxmips_mii_hw_receive_err_exit;
136         }
137
138         skb_put(skb, len);
139         skb->dev = dev;
140         skb->protocol = eth_type_trans(skb, dev);
141         netif_rx(skb);
142
143         priv->stats.rx_packets++;
144         priv->stats.rx_bytes += len;
145         return 0;
146
147 ifxmips_mii_hw_receive_err_exit:
148         if (len == 0)
149         {
150                 if (skb)
151                         dev_kfree_skb_any(skb);
152                 priv->stats.rx_errors++;
153                 priv->stats.rx_dropped++;
154                 return -EIO;
155         } else {
156                 return len;
157         }
158 }
159
160 int
161 ifxmips_mii_hw_tx(char *buf, int len, struct net_device *dev)
162 {
163         int ret = 0;
164         struct ifxmips_mii_priv *priv = dev->priv;
165         struct dma_device_info* dma_dev = priv->dma_device;
166         ret = dma_device_write(dma_dev, buf, len, priv->skb);
167         return ret;
168 }
169
170 int
171 ifxmips_mii_tx(struct sk_buff *skb, struct net_device *dev)
172 {
173         int len;
174         char *data;
175         struct ifxmips_mii_priv *priv = dev->priv;
176         struct dma_device_info* dma_dev = priv->dma_device;
177
178         len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
179         data = skb->data;
180         priv->skb = skb;
181         dev->trans_start = jiffies;
182         // TODO we got more than 1 dma channel, so we should do something intelligent
183         // here to select one
184         dma_dev->current_tx_chan = 0;
185
186         wmb();
187
188         if (ifxmips_mii_hw_tx(data, len, dev) != len)
189         {
190                 dev_kfree_skb_any(skb);
191                 priv->stats.tx_errors++;
192                 priv->stats.tx_dropped++;
193         } else {
194                 priv->stats.tx_packets++;
195                 priv->stats.tx_bytes+=len;
196         }
197
198         return 0;
199 }
200
201 void
202 ifxmips_mii_tx_timeout(struct net_device *dev)
203 {
204         int i;
205         struct ifxmips_mii_priv* priv = (struct ifxmips_mii_priv*)dev->priv;
206
207         priv->stats.tx_errors++;
208         for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
209                 priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
210         netif_wake_queue(dev);
211         return;
212 }
213
214 int
215 dma_intr_handler(struct dma_device_info* dma_dev, int status)
216 {
217         int i;
218
219         switch(status)
220         {
221         case RCV_INT:
222                 ifxmips_mii_hw_receive(ifxmips_mii0_dev, dma_dev);
223                 break;
224
225         case TX_BUF_FULL_INT:
226                 printk(KERN_INFO "ifxmips_mii0: tx buffer full\n");
227                 netif_stop_queue(ifxmips_mii0_dev);
228                 for (i = 0; i < dma_dev->max_tx_chan_num; i++)
229                 {
230                         if ((dma_dev->tx_chan[i])->control==IFXMIPS_DMA_CH_ON)
231                                 dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
232                 }
233                 break;
234
235         case TRANSMIT_CPT_INT:
236                 for (i = 0; i < dma_dev->max_tx_chan_num; i++)
237                         dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
238
239                 netif_wake_queue(ifxmips_mii0_dev);
240                 break;
241         }
242
243         return 0;
244 }
245
246 unsigned char*
247 ifxmips_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
248 {
249         unsigned char *buffer = NULL;
250         struct sk_buff *skb = NULL;
251
252         skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
253         if (skb == NULL)
254                 return NULL;
255
256         buffer = (unsigned char*)(skb->data);
257         skb_reserve(skb, 2);
258         *(int*)opt = (int)skb;
259         *byte_offset = 2;
260
261         return buffer;
262 }
263
264 void
265 ifxmips_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
266 {
267         struct sk_buff *skb = NULL;
268
269         if (opt == NULL)
270         {
271                 kfree(dataptr);
272         } else {
273                 skb = (struct sk_buff*)opt;
274                 dev_kfree_skb_any(skb);
275         }
276 }
277
278 static struct net_device_stats*
279 ifxmips_get_stats(struct net_device *dev)
280 {
281         return (struct net_device_stats *)dev->priv;
282 }
283
284 static int
285 ifxmips_mii_dev_init(struct net_device *dev)
286 {
287         int i;
288         struct ifxmips_mii_priv *priv;
289
290         ether_setup(dev);
291         printk(KERN_INFO "ifxmips_mii0: %s is up\n", dev->name);
292         dev->open = ifxmips_ifxmips_mii_open;
293         dev->stop = ifxmips_mii_release;
294         dev->hard_start_xmit = ifxmips_mii_tx;
295         dev->get_stats = ifxmips_get_stats;
296         dev->tx_timeout = ifxmips_mii_tx_timeout;
297         dev->watchdog_timeo = 10 * HZ;
298         memset(dev->priv, 0, sizeof(struct ifxmips_mii_priv));
299         priv = dev->priv;
300         priv->dma_device = dma_device_reserve("PPE");
301         if (!priv->dma_device){
302                 BUG();
303                 return -ENODEV;
304         }
305         priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc;
306         priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free;
307         priv->dma_device->intr_handler = &dma_intr_handler;
308         priv->dma_device->max_rx_chan_num = 4;
309
310         for (i = 0; i < priv->dma_device->max_rx_chan_num; i++)
311         {
312                 priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
313                 priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON;
314         }
315
316         for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
317                 if (i == 0)
318                         priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON;
319                 else
320                         priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF;
321
322         dma_device_register(priv->dma_device);
323
324         printk(KERN_INFO "ifxmips_mii0: using mac=");
325         for (i = 0; i < 6; i++)
326         {
327                 dev->dev_addr[i] = mac_addr[i];
328                 printk("%02X%c", dev->dev_addr[i], (i == 5)?('\n'):(':'));
329         }
330         return 0;
331 }
332
333 static void
334 ifxmips_mii_chip_init(int mode)
335 {
336         ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA);
337         ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE);
338
339         if (mode == REV_MII_MODE)
340                 ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG);
341         else if (mode == MII_MODE)
342                 ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG);
343         ifxmips_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL);
344         ifxmips_w32(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG);
345         wmb();
346 }
347
348 static int
349 ifxmips_mii_probe(struct platform_device *dev)
350 {
351         int result = 0;
352         unsigned char *mac = (unsigned char*)dev->dev.platform_data;
353         ifxmips_mii0_dev = alloc_etherdev(sizeof(struct ifxmips_mii_priv));
354         ifxmips_mii0_dev->init = ifxmips_mii_dev_init;
355         memcpy(mac_addr, mac, 6);
356         strcpy(ifxmips_mii0_dev->name, "eth%d");
357         ifxmips_mii_chip_init(REV_MII_MODE);
358         result = register_netdev(ifxmips_mii0_dev);
359         if (result)
360         {
361                 printk(KERN_INFO "ifxmips_mii0: error %i registering device \"%s\"\n", result, ifxmips_mii0_dev->name);
362                 goto out;
363         }
364
365         printk(KERN_INFO "ifxmips_mii0: driver loaded!\n");
366
367 out:
368         return result;
369 }
370
371 static int
372 ifxmips_mii_remove(struct platform_device *dev)
373 {
374         struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv*)ifxmips_mii0_dev->priv;
375
376         printk(KERN_INFO "ifxmips_mii0: ifxmips_mii0 cleanup\n");
377
378         dma_device_unregister(priv->dma_device);
379         dma_device_release(priv->dma_device);
380         kfree(priv->dma_device);
381         kfree(ifxmips_mii0_dev->priv);
382         unregister_netdev(ifxmips_mii0_dev);
383         return 0;
384 }
385
386 static struct
387 platform_driver ifxmips_mii_driver = {
388         .probe = ifxmips_mii_probe,
389         .remove = ifxmips_mii_remove,
390         .driver = {
391                 .name = "ifxmips_mii0",
392                 .owner = THIS_MODULE,
393         },
394 };
395
396 int __init
397 ifxmips_mii_init(void)
398 {
399         int ret = platform_driver_register(&ifxmips_mii_driver);
400         if (ret)
401                 printk(KERN_INFO "ifxmips_mii0: Error registering platfom driver!");
402         return ret;
403 }
404
405 static void __exit
406 ifxmips_mii_cleanup(void)
407 {
408         platform_driver_unregister(&ifxmips_mii_driver);
409 }
410
411 module_init(ifxmips_mii_init);
412 module_exit(ifxmips_mii_cleanup);
413
414 MODULE_LICENSE("GPL");
415 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
416 MODULE_DESCRIPTION("ethernet map driver for IFXMIPS boards");