Root/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch

1Index: linux-2.6.30.8/drivers/net/Kconfig
2===================================================================
3--- linux-2.6.30.8.orig/drivers/net/Kconfig 2009-10-19 21:31:30.000000000 +0200
4+++ linux-2.6.30.8/drivers/net/Kconfig 2009-10-19 21:31:32.000000000 +0200
5@@ -353,6 +353,12 @@
6 
7 source "drivers/net/arm/Kconfig"
8 
9+config IFXMIPS_MII0
10+ tristate "Infineon IFXMips eth0 driver"
11+ depends on IFXMIPS
12+ help
13+ Support for the MII0 inside the IFXMips SOC
14+
15 config AX88796
16     tristate "ASIX AX88796 NE2000 clone support"
17     depends on ARM || MIPS || SUPERH
18Index: linux-2.6.30.8/drivers/net/Makefile
19===================================================================
20--- linux-2.6.30.8.orig/drivers/net/Makefile 2009-10-19 21:31:30.000000000 +0200
21+++ linux-2.6.30.8/drivers/net/Makefile 2009-10-19 21:31:32.000000000 +0200
22@@ -234,6 +234,7 @@
23 obj-$(CONFIG_MLX4_CORE) += mlx4/
24 obj-$(CONFIG_ENC28J60) += enc28j60.o
25 obj-$(CONFIG_ETHOC) += ethoc.o
26+obj-$(CONFIG_IFXMIPS_MII0) += ifxmips_mii0.o
27 
28 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
29 
30Index: linux-2.6.30.8/drivers/net/ifxmips_mii0.c
31===================================================================
32--- /dev/null 2010-01-25 20:01:36.843225078 +0100
33+++ linux-2.6.30.10/drivers/net/ifxmips_mii0.c 2010-03-13 19:04:25.000000000 +0100
34@@ -0,0 +1,489 @@
35+/*
36+ * This program is free software; you can redistribute it and/or modify
37+ * it under the terms of the GNU General Public License as published by
38+ * the Free Software Foundation; either version 2 of the License, or
39+ * (at your option) any later version.
40+ *
41+ * This program is distributed in the hope that it will be useful,
42+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
43+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44+ * GNU General Public License for more details.
45+ *
46+ * You should have received a copy of the GNU General Public License
47+ * along with this program; if not, write to the Free Software
48+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
49+ *
50+ * Copyright (C) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
51+ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
52+ */
53+
54+#include <linux/kernel.h>
55+#include <linux/slab.h>
56+#include <linux/errno.h>
57+#include <linux/types.h>
58+#include <linux/interrupt.h>
59+#include <linux/uaccess.h>
60+#include <linux/in.h>
61+#include <linux/netdevice.h>
62+#include <linux/etherdevice.h>
63+#include <linux/phy.h>
64+#include <linux/ip.h>
65+#include <linux/tcp.h>
66+#include <linux/skbuff.h>
67+#include <linux/mm.h>
68+#include <linux/platform_device.h>
69+#include <linux/ethtool.h>
70+#include <linux/init.h>
71+#include <linux/delay.h>
72+
73+#include <asm/checksum.h>
74+
75+#include <ifxmips.h>
76+#include <ifxmips_dma.h>
77+#include <ifxmips_pmu.h>
78+
79+struct ifxmips_mii_priv {
80+ struct net_device_stats stats;
81+ struct dma_device_info *dma_device;
82+ struct sk_buff *skb;
83+
84+ struct mii_bus *mii_bus;
85+ struct phy_device *phydev;
86+ int oldlink, oldspeed, oldduplex;
87+};
88+
89+static struct net_device *ifxmips_mii0_dev;
90+static unsigned char mac_addr[MAX_ADDR_LEN];
91+
92+static int ifxmips_mdiobus_write(struct mii_bus *bus, int phy_addr,
93+ int phy_reg, u16 phy_data)
94+{
95+ u32 val = MDIO_ACC_REQUEST |
96+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
97+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) |
98+ phy_data;
99+
100+ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
101+ ;
102+ ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
103+
104+ return 0;
105+}
106+
107+static int ifxmips_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg)
108+{
109+ u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ |
110+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
111+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET);
112+
113+ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
114+ ;
115+ ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC);
116+ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
117+ ;
118+ val = ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK;
119+ return val;
120+}
121+
122+int ifxmips_ifxmips_mii_open(struct net_device *dev)
123+{
124+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
125+ struct dma_device_info *dma_dev = priv->dma_device;
126+ int i;
127+
128+ for (i = 0; i < dma_dev->max_rx_chan_num; i++) {
129+ if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON)
130+ (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]);
131+ }
132+ netif_start_queue(dev);
133+ return 0;
134+}
135+
136+int ifxmips_mii_release(struct net_device *dev)
137+{
138+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
139+ struct dma_device_info *dma_dev = priv->dma_device;
140+ int i;
141+
142+ for (i = 0; i < dma_dev->max_rx_chan_num; i++)
143+ dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
144+ netif_stop_queue(dev);
145+ return 0;
146+}
147+
148+int ifxmips_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
149+{
150+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
151+ unsigned char *buf = NULL;
152+ struct sk_buff *skb = NULL;
153+ int len = 0;
154+
155+ len = dma_device_read(dma_dev, &buf, (void **)&skb);
156+
157+ if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) {
158+ printk(KERN_INFO "ifxmips_mii0: packet too large %d\n", len);
159+ goto ifxmips_mii_hw_receive_err_exit;
160+ }
161+
162+ /* remove CRC */
163+ len -= 4;
164+ if (skb == NULL) {
165+ printk(KERN_INFO "ifxmips_mii0: cannot restore pointer\n");
166+ goto ifxmips_mii_hw_receive_err_exit;
167+ }
168+
169+ if (len > (skb->end - skb->tail)) {
170+ printk(KERN_INFO "ifxmips_mii0: BUG, len:%d end:%p tail:%p\n",
171+ (len+4), skb->end, skb->tail);
172+ goto ifxmips_mii_hw_receive_err_exit;
173+ }
174+
175+ skb_put(skb, len);
176+ skb->dev = dev;
177+ skb->protocol = eth_type_trans(skb, dev);
178+ netif_rx(skb);
179+
180+ priv->stats.rx_packets++;
181+ priv->stats.rx_bytes += len;
182+ return 0;
183+
184+ifxmips_mii_hw_receive_err_exit:
185+ if (len == 0) {
186+ if (skb)
187+ dev_kfree_skb_any(skb);
188+ priv->stats.rx_errors++;
189+ priv->stats.rx_dropped++;
190+ return -EIO;
191+ } else {
192+ return len;
193+ }
194+}
195+
196+int ifxmips_mii_hw_tx(char *buf, int len, struct net_device *dev)
197+{
198+ int ret = 0;
199+ struct ifxmips_mii_priv *priv = netdev_priv(dev);
200+ struct dma_device_info *dma_dev = priv->dma_device;
201+ ret = dma_device_write(dma_dev, buf, len, priv->skb);
202+ return ret;
203+}
204+
205+int ifxmips_mii_tx(struct sk_buff *skb, struct net_device *dev)
206+{
207+ int len;
208+ char *data;
209+ struct ifxmips_mii_priv *priv = netdev_priv(dev);
210+ struct dma_device_info *dma_dev = priv->dma_device;
211+
212+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
213+ data = skb->data;
214+ priv->skb = skb;
215+ dev->trans_start = jiffies;
216+ /* TODO: we got more than 1 dma channel,
217+ so we should do something intelligent here to select one */
218+ dma_dev->current_tx_chan = 0;
219+
220+ wmb();
221+
222+ if (ifxmips_mii_hw_tx(data, len, dev) != len) {
223+ dev_kfree_skb_any(skb);
224+ priv->stats.tx_errors++;
225+ priv->stats.tx_dropped++;
226+ } else {
227+ priv->stats.tx_packets++;
228+ priv->stats.tx_bytes += len;
229+ }
230+
231+ return 0;
232+}
233+
234+void ifxmips_mii_tx_timeout(struct net_device *dev)
235+{
236+ int i;
237+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
238+
239+ priv->stats.tx_errors++;
240+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
241+ priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
242+ netif_wake_queue(dev);
243+ return;
244+}
245+
246+int dma_intr_handler(struct dma_device_info *dma_dev, int status)
247+{
248+ int i;
249+
250+ switch (status) {
251+ case RCV_INT:
252+ ifxmips_mii_hw_receive(ifxmips_mii0_dev, dma_dev);
253+ break;
254+
255+ case TX_BUF_FULL_INT:
256+ printk(KERN_INFO "ifxmips_mii0: tx buffer full\n");
257+ netif_stop_queue(ifxmips_mii0_dev);
258+ for (i = 0; i < dma_dev->max_tx_chan_num; i++) {
259+ if ((dma_dev->tx_chan[i])->control == IFXMIPS_DMA_CH_ON)
260+ dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
261+ }
262+ break;
263+
264+ case TRANSMIT_CPT_INT:
265+ for (i = 0; i < dma_dev->max_tx_chan_num; i++)
266+ dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
267+
268+ netif_wake_queue(ifxmips_mii0_dev);
269+ break;
270+ }
271+
272+ return 0;
273+}
274+
275+unsigned char *ifxmips_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
276+{
277+ unsigned char *buffer = NULL;
278+ struct sk_buff *skb = NULL;
279+
280+ skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
281+ if (skb == NULL)
282+ return NULL;
283+
284+ buffer = (unsigned char *)(skb->data);
285+ skb_reserve(skb, 2);
286+ *(int *)opt = (int)skb;
287+ *byte_offset = 2;
288+
289+ return buffer;
290+}
291+
292+void ifxmips_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
293+{
294+ struct sk_buff *skb = NULL;
295+
296+ if (opt == NULL) {
297+ kfree(dataptr);
298+ } else {
299+ skb = (struct sk_buff *)opt;
300+ dev_kfree_skb_any(skb);
301+ }
302+}
303+
304+static struct net_device_stats *ifxmips_get_stats(struct net_device *dev)
305+{
306+ return &((struct ifxmips_mii_priv *)netdev_priv(dev))->stats;
307+}
308+
309+static void
310+ifxmips_adjust_link(struct net_device *dev)
311+{
312+ struct ifxmips_mii_priv *priv = netdev_priv(dev);
313+ struct phy_device *phydev = priv->phydev;
314+ int new_state = 0;
315+
316+ /* Did anything change? */
317+ if (priv->oldlink != phydev->link ||
318+ priv->oldduplex != phydev->duplex ||
319+ priv->oldspeed != phydev->speed) {
320+ /* Yes, so update status and mark as changed */
321+ new_state = 1;
322+ priv->oldduplex = phydev->duplex;
323+ priv->oldspeed = phydev->speed;
324+ priv->oldlink = phydev->link;
325+ }
326+
327+ /* If link status changed, show new status */
328+ if (new_state)
329+ phy_print_status(phydev);
330+}
331+
332+static int mii_probe(struct net_device *dev)
333+{
334+ struct ifxmips_mii_priv *priv = netdev_priv(dev);
335+ struct phy_device *phydev = NULL;
336+ int phy_addr;
337+
338+ priv->oldlink = 0;
339+ priv->oldspeed = 0;
340+ priv->oldduplex = -1;
341+
342+ /* find the first (lowest address) PHY on the current MAC's MII bus */
343+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
344+ if (priv->mii_bus->phy_map[phy_addr]) {
345+ phydev = priv->mii_bus->phy_map[phy_addr];
346+ break; /* break out with first one found */
347+ }
348+ }
349+
350+ if (!phydev) {
351+ printk (KERN_ERR "%s: no PHY found\n", dev->name);
352+ return -ENODEV;
353+ }
354+
355+ /* now we are supposed to have a proper phydev, to attach to... */
356+ BUG_ON(!phydev);
357+ BUG_ON(phydev->attached_dev);
358+
359+ phydev = phy_connect(dev, dev_name(&phydev->dev), &ifxmips_adjust_link,
360+ 0, PHY_INTERFACE_MODE_MII);
361+
362+ if (IS_ERR(phydev)) {
363+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
364+ return PTR_ERR(phydev);
365+ }
366+
367+ /* mask with MAC supported features */
368+ phydev->supported &= (SUPPORTED_10baseT_Half
369+ | SUPPORTED_10baseT_Full
370+ | SUPPORTED_100baseT_Half
371+ | SUPPORTED_100baseT_Full
372+ | SUPPORTED_Autoneg
373+ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
374+ | SUPPORTED_MII
375+ | SUPPORTED_TP);
376+
377+ phydev->advertising = phydev->supported;
378+
379+ priv->phydev = phydev;
380+
381+ printk(KERN_INFO "%s: attached PHY driver [%s] "
382+ "(mii_bus:phy_addr=%s, irq=%d)\n",
383+ dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
384+
385+ return 0;
386+}
387+
388+
389+static int ifxmips_mii_dev_init(struct net_device *dev)
390+{
391+ int i;
392+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev);
393+ ether_setup(dev);
394+ dev->open = ifxmips_ifxmips_mii_open;
395+ dev->stop = ifxmips_mii_release;
396+ dev->hard_start_xmit = ifxmips_mii_tx;
397+ dev->get_stats = ifxmips_get_stats;
398+ dev->tx_timeout = ifxmips_mii_tx_timeout;
399+ dev->watchdog_timeo = 10 * HZ;
400+ memset(priv, 0, sizeof(struct ifxmips_mii_priv));
401+ priv->dma_device = dma_device_reserve("PPE");
402+ if (!priv->dma_device) {
403+ BUG();
404+ return -ENODEV;
405+ }
406+ priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc;
407+ priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free;
408+ priv->dma_device->intr_handler = &dma_intr_handler;
409+ priv->dma_device->max_rx_chan_num = 4;
410+
411+ for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) {
412+ priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
413+ priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON;
414+ }
415+
416+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
417+ if (i == 0)
418+ priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON;
419+ else
420+ priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF;
421+
422+ dma_device_register(priv->dma_device);
423+
424+ printk(KERN_INFO "%s: using mac=", dev->name);
425+ for (i = 0; i < 6; i++) {
426+ dev->dev_addr[i] = mac_addr[i];
427+ printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':'));
428+ }
429+
430+ priv->mii_bus = mdiobus_alloc();
431+ if (priv->mii_bus == NULL)
432+ return -ENOMEM;
433+
434+ priv->mii_bus->priv = dev;
435+ priv->mii_bus->read = ifxmips_mdiobus_read;
436+ priv->mii_bus->write = ifxmips_mdiobus_write;
437+ priv->mii_bus->name = "ifxmips_mii";
438+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
439+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
440+ for(i = 0; i < PHY_MAX_ADDR; ++i)
441+ priv->mii_bus->irq[i] = PHY_POLL;
442+
443+ mdiobus_register(priv->mii_bus);
444+
445+ return mii_probe(dev);
446+}
447+
448+static void ifxmips_mii_chip_init(int mode)
449+{
450+ ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA);
451+ ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE);
452+
453+ if (mode == REV_MII_MODE)
454+ ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG);
455+ else if (mode == MII_MODE)
456+ ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG);
457+ ifxmips_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL);
458+ ifxmips_w32(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG);
459+ wmb();
460+}
461+
462+static int ifxmips_mii_probe(struct platform_device *dev)
463+{
464+ int result = 0;
465+ unsigned char *mac = (unsigned char *)dev->dev.platform_data;
466+ ifxmips_mii0_dev = alloc_etherdev(sizeof(struct ifxmips_mii_priv));
467+ ifxmips_mii0_dev->init = ifxmips_mii_dev_init;
468+ memcpy(mac_addr, mac, 6);
469+ strcpy(ifxmips_mii0_dev->name, "eth%d");
470+ ifxmips_mii_chip_init(REV_MII_MODE);
471+ result = register_netdev(ifxmips_mii0_dev);
472+ if (result) {
473+ printk(KERN_INFO "ifxmips_mii0: error %i registering device \"%s\"\n", result, ifxmips_mii0_dev->name);
474+ goto out;
475+ }
476+
477+ printk(KERN_INFO "ifxmips_mii0: driver loaded!\n");
478+
479+out:
480+ return result;
481+}
482+
483+static int ifxmips_mii_remove(struct platform_device *dev)
484+{
485+ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(ifxmips_mii0_dev);
486+
487+ printk(KERN_INFO "ifxmips_mii0: ifxmips_mii0 cleanup\n");
488+
489+ dma_device_unregister(priv->dma_device);
490+ dma_device_release(priv->dma_device);
491+ kfree(priv->dma_device);
492+ unregister_netdev(ifxmips_mii0_dev);
493+ return 0;
494+}
495+
496+static struct platform_driver ifxmips_mii_driver = {
497+ .probe = ifxmips_mii_probe,
498+ .remove = ifxmips_mii_remove,
499+ .driver = {
500+ .name = "ifxmips_mii0",
501+ .owner = THIS_MODULE,
502+ },
503+};
504+
505+int __init ifxmips_mii_init(void)
506+{
507+ int ret = platform_driver_register(&ifxmips_mii_driver);
508+ if (ret)
509+ printk(KERN_INFO "ifxmips_mii0: Error registering platfom driver!");
510+ return ret;
511+}
512+
513+static void __exit ifxmips_mii_cleanup(void)
514+{
515+ platform_driver_unregister(&ifxmips_mii_driver);
516+}
517+
518+module_init(ifxmips_mii_init);
519+module_exit(ifxmips_mii_cleanup);
520+
521+MODULE_LICENSE("GPL");
522+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
523+MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards");
524+
525

Archive Download this file



interactive