source: trunk/target/linux/ifxmips/files/drivers/net/ifxmips_mii0.c @ 11396

Last change on this file since 11396 was 11396, checked in by blogic, 9 years ago

fixes ifxmips pci support and adds GENERIC_GPIO

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